NVIDIA DOCA SDK Data Center on a Chip Framework Documentation
ipsec_security_gw.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2022-2024 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 #include <signal.h>
26 #include <fcntl.h>
27 
28 #include <rte_ethdev.h>
29 
30 #include <doca_argp.h>
31 #include <doca_flow_tune_server.h>
32 #include <doca_log.h>
33 #include <doca_pe.h>
34 #include <doca_dev.h>
35 
36 #include <dpdk_utils.h>
37 #include <pack.h>
38 
39 #include "config.h"
40 #include "flow_common.h"
41 #include "flow_decrypt.h"
42 #include "flow_encrypt.h"
43 #include "ipsec_ctx.h"
44 #include "policy.h"
45 
46 DOCA_LOG_REGISTER(IPSEC_SECURITY_GW);
47 
48 #define DEFAULT_NB_CORES 4 /* Default number of running cores */
49 #define PACKET_BURST 32 /* The number of packets in the rx queue */
50 #define NB_TX_BURST_TRIES 5 /* Number of tries for sending batch of packets */
51 #define MIN_ENTRIES_PER_CORE 1024 /* Minimum number of entries per core */
52 #define MAC_ADDRESS_SIZE 6 /* Size of mac address */
53 
54 /* Rule Inserter worker thread context struct */
56  struct ipsec_security_gw_config *app_cfg; /* Application configuration struct */
57  struct ipsec_security_gw_ports_map **ports; /* Application ports */
58  int queue_id; /* Queue ID */
59  int nb_encrypt_rules; /* Number of encryption rules */
60  int nb_decrypt_rules; /* Number of decryption rules */
61  int encrypt_rule_offset; /* Offset for encryption rules */
62  int decrypt_rule_offset; /* Offset for decryption rules */
63 };
64 
65 static bool force_quit; /* Set when signal is received */
66 static char *syndrome_list[NUM_OF_SYNDROMES] = {"Authentication failed",
67  "Trailer length exceeded ESP payload",
68  "Replay protection failed",
69  "IPsec offload context reached its hard lifetime threshold"};
70 
71 /*
72  * Signals handler function to handle SIGINT and SIGTERM signals
73  *
74  * @signum [in]: signal number
75  */
76 static void signal_handler(int signum)
77 {
78  if (signum == SIGINT || signum == SIGTERM) {
79  DOCA_LOG_INFO("Signal %d received, preparing to exit", signum);
80  force_quit = true;
81  }
82 }
83 
84 /*
85  * Query all the entries in the pipe and print the changed entries
86  *
87  * @pipe [in]: pipe to query
88  * @return: true if packet hit an entry in the pipe since last query
89  */
91 {
93  struct doca_flow_resource_query query_stats;
94  uint64_t delta;
95  uint32_t i;
96  bool first = true;
97 
98  for (i = 0; i < pipe->nb_entries; i++) {
99  result = doca_flow_resource_query_entry(pipe->entries_info[i].entry, &query_stats);
100  if (result != DOCA_SUCCESS) {
101  DOCA_LOG_ERR("Failed to query entry: %s", doca_error_get_descr(result));
102  continue;
103  }
104  if (query_stats.counter.total_pkts != pipe->entries_info[i].prev_stats) {
105  delta = query_stats.counter.total_pkts - pipe->entries_info[i].prev_stats;
106  if (first) {
107  printf("%s[%s:%ld", pipe->name, pipe->entries_info[i].name, delta);
108  first = false;
109  } else
110  printf(",%s:%ld", pipe->entries_info[i].name, delta);
111  pipe->entries_info[i].prev_stats = query_stats.counter.total_pkts;
112  }
113  }
114  if (!first)
115  printf("] ");
116  return !first;
117 }
118 /*
119  * Query all the entries of bad syndrome of a specific rule, print the delta from last query if different from 0
120  *
121  * @decrypt_rule [in]: the rule to query its entries
122  */
124 {
126  struct doca_flow_resource_query query_stats;
127  int i;
128 
129  for (i = 0; i < NUM_OF_SYNDROMES; i++) {
131  if (result != DOCA_SUCCESS) {
132  DOCA_LOG_ERR("Failed to query entry: %s", doca_error_get_descr(result));
133  continue;
134  }
135  if (query_stats.counter.total_pkts != decrypt_rule->entries[i].previous_stats) {
137  DOCA_LOG_INFO("Spi %d, IP %d.%d.%d.%d",
139  (decrypt_rule->dst_ip4) & 0xFF,
140  (decrypt_rule->dst_ip4 >> 8) & 0xFF,
141  (decrypt_rule->dst_ip4 >> 16) & 0xFF,
142  (decrypt_rule->dst_ip4 >> 24) & 0xFF);
143  } else {
144  char ipinput[INET6_ADDRSTRLEN];
145 
146  inet_ntop(AF_INET6, &(decrypt_rule->dst_ip6), ipinput, INET6_ADDRSTRLEN);
147  DOCA_LOG_INFO("Spi %d, IP %s", decrypt_rule->esp_spi, ipinput);
148  }
149  DOCA_LOG_INFO("Got bad syndrome: %s, number of hits since last dump: %ld",
150  syndrome_list[i],
151  query_stats.counter.total_pkts - decrypt_rule->entries[i].previous_stats);
152  decrypt_rule->entries[i].previous_stats = query_stats.counter.total_pkts;
153  }
154  }
155 }
156 
157 /*
158  * Query all the encrypt pipes
159  *
160  * @app_cfg [in]: application configuration structure
161  */
163 {
164  bool changed = false;
165 
166  if (app_cfg->flow_mode == IPSEC_SECURITY_GW_SWITCH)
167  changed |= query_pipe_info(&app_cfg->encrypt_pipes.encrypt_root);
168  changed |= query_pipe_info(&app_cfg->encrypt_pipes.ipv4_tcp_pipe);
169  changed |= query_pipe_info(&app_cfg->encrypt_pipes.ipv4_udp_pipe);
170  changed |= query_pipe_info(&app_cfg->encrypt_pipes.ipv6_tcp_pipe);
171  changed |= query_pipe_info(&app_cfg->encrypt_pipes.ipv6_udp_pipe);
172  changed |= query_pipe_info(&app_cfg->encrypt_pipes.ipv6_src_tcp_pipe);
173  changed |= query_pipe_info(&app_cfg->encrypt_pipes.ipv6_src_udp_pipe);
174  changed |= query_pipe_info(&app_cfg->encrypt_pipes.egress_ip_classifier);
175  changed |= query_pipe_info(&app_cfg->encrypt_pipes.ipv4_encrypt_pipe);
176  changed |= query_pipe_info(&app_cfg->encrypt_pipes.ipv6_encrypt_pipe);
177  changed |= query_pipe_info(&app_cfg->encrypt_pipes.marker_insert_pipe);
178  if (app_cfg->vxlan_encap)
179  changed |= query_pipe_info(&app_cfg->encrypt_pipes.vxlan_encap_pipe);
180  if (changed)
181  printf("\n");
182 }
183 
184 /*
185  * Query all the decrypt pipes
186  *
187  * @app_cfg [in]: application configuration structure
188  */
190 {
191  bool changed = false;
192 
193  changed |= query_pipe_info(&app_cfg->decrypt_pipes.vxlan_decap_ipv4_pipe);
194  changed |= query_pipe_info(&app_cfg->decrypt_pipes.vxlan_decap_ipv6_pipe);
195  changed |= query_pipe_info(&app_cfg->decrypt_pipes.decrypt_ipv4_pipe);
196  changed |= query_pipe_info(&app_cfg->decrypt_pipes.decrypt_ipv6_pipe);
197  changed |= query_pipe_info(&app_cfg->decrypt_pipes.decap_pipe);
198  changed |= query_pipe_info(&app_cfg->decrypt_pipes.marker_remove_pipe);
199  if (changed)
200  printf("\n");
201 }
202 
203 /*
204  * Query the entries that dropped packet with bad syndrome
205  *
206  * @args [in]: generic pointer to core context struct
207  */
208 static void process_syndrome_packets(void *args)
209 {
211  int i;
212  uint64_t start_time, end_time;
213  double delta;
214  double cycle_time = 5;
215  uint64_t max_timeout = 4000000;
216  uint32_t max_resources = ctx->config->app_rules.nb_decrypt_rules + ctx->config->app_rules.nb_encrypt_rules;
217 
218  while (!force_quit) {
219  start_time = rte_get_timer_cycles();
220  doca_flow_crypto_ipsec_resource_handle(ctx->ports[SECURED_IDX]->port, max_timeout, max_resources);
221  if (ctx->config->debug_mode) {
222  query_encrypt_pipes(ctx->config);
223  query_decrypt_pipes(ctx->config);
224  for (i = 0; i < ctx->config->app_rules.nb_decrypt_rules; i++)
225  query_bad_syndrome(&ctx->config->app_rules.decrypt_rules[i]);
226  }
227  end_time = rte_get_timer_cycles();
228  delta = (end_time - start_time) / rte_get_timer_hz();
229  if (delta < cycle_time)
230  sleep(cycle_time - delta);
231  }
232  free(ctx);
233 }
234 
235 /*
236  * Return true if we run in debug mode and send the bad syndrome packets to RSS queue
237  *
238  * @app_cfg [in]: application configuration struct
239  * @return: true if we send the bad syndrome packets to RSS
240  */
242 {
243  return (app_cfg->debug_mode && app_cfg->syndrome_fwd == IPSEC_SECURITY_GW_FWD_SYNDROME_RSS);
244 }
245 
246 /*
247  * Handling the new received packet, send to process encap or decap based on src port
248  *
249  * @port_id [in]: port ID
250  * @nb_packets [in]: size of mbufs array
251  * @packets [in]: array of packets
252  * @ctx [in]: core context struct
253  * @nb_processed_packets [out]: number of processed packets
254  * @processed_packets [out]: array of processed packets
255  * @unprocessed_packets [out]: array of unprocessed packets
256  */
257 static void handle_packets_received(uint16_t port_id,
258  uint16_t nb_packets,
259  struct rte_mbuf **packets,
261  uint16_t *nb_processed_packets,
262  struct rte_mbuf **processed_packets,
263  struct rte_mbuf **unprocessed_packets)
264 {
265  uint32_t current_packet;
266  uint32_t pkt_meta;
267  bool encrypt;
268  int unprocessed_packets_idx = 0;
270 
271  *nb_processed_packets = 0;
272 
273  for (current_packet = 0; current_packet < nb_packets; current_packet++) {
274  if (ctx->config->flow_mode == IPSEC_SECURITY_GW_SWITCH) {
275  pkt_meta = *RTE_FLOW_DYNF_METADATA(packets[current_packet]);
276  encrypt = ((union security_gateway_pkt_meta)pkt_meta).encrypt;
277  if (encrypt)
278  port_id = ctx->ports[UNSECURED_IDX]->port_id;
279  else
280  port_id = ctx->ports[SECURED_IDX]->port_id;
281  }
282  if (port_id == (ctx->ports[UNSECURED_IDX])->port_id)
283  result = handle_unsecured_packets_received(&packets[current_packet], ctx);
284  else
285  result = handle_secured_packets_received(&packets[current_packet],
286  is_fwd_syndrome_rss(ctx->config),
287  ctx);
288  if (result != DOCA_SUCCESS)
289  goto add_dropped;
290 
291  processed_packets[(*nb_processed_packets)++] = packets[current_packet];
292  continue;
293 
294 add_dropped:
295  unprocessed_packets[unprocessed_packets_idx++] = packets[current_packet];
296  }
297 }
298 
299 /*
300  * Receive the income packets from the RX queue process them, and send it to the TX queue in the second port
301  *
302  * @args [in]: generic pointer to core context struct
303  */
304 static void process_queue_packets(void *args)
305 {
306  uint16_t port_id;
307  uint16_t nb_packets_received;
308  uint16_t nb_processed_packets = 0;
309  uint16_t nb_packets_to_drop;
310  struct rte_mbuf *packets[PACKET_BURST];
311  struct rte_mbuf *processed_packets[PACKET_BURST] = {0};
312  struct rte_mbuf *packets_to_drop[PACKET_BURST] = {0};
313  int nb_pkts;
314  int num_of_tries = NB_TX_BURST_TRIES;
316  uint16_t nb_ports = ctx->config->dpdk_config->port_config.nb_ports;
317  uint16_t tx_port;
318 
319  DOCA_LOG_DBG("Core %u is receiving packets", rte_lcore_id());
320  while (!force_quit) {
321  for (port_id = 0; port_id < nb_ports; port_id++) {
322  nb_packets_received = rte_eth_rx_burst(port_id, ctx->queue_id, packets, PACKET_BURST);
323  if (nb_packets_received) {
324  DOCA_LOG_TRC("Received %d packets from port %d on core %u",
325  nb_packets_received,
326  port_id,
327  rte_lcore_id());
328  handle_packets_received(port_id,
329  nb_packets_received,
330  packets,
331  ctx,
332  &nb_processed_packets,
333  processed_packets,
334  packets_to_drop);
335  nb_pkts = 0;
336  if (ctx->config->flow_mode == IPSEC_SECURITY_GW_VNF) {
337  tx_port = port_id ^ 1;
338  } else {
339  tx_port = port_id;
340  }
341  do {
342  nb_pkts += rte_eth_tx_burst(tx_port,
343  ctx->queue_id,
344  processed_packets + nb_pkts,
345  nb_processed_packets - nb_pkts);
346  num_of_tries--;
347  } while (nb_processed_packets > nb_pkts && num_of_tries > 0);
348  if (nb_processed_packets > nb_pkts)
350  "%d packets were dropped during the transmission to the next port",
351  (nb_processed_packets - nb_pkts));
352  nb_packets_to_drop = nb_packets_received - nb_processed_packets;
353  if (nb_packets_to_drop > 0) {
354  DOCA_LOG_WARN("%d packets were dropped during the processing",
355  nb_packets_to_drop);
356  rte_pktmbuf_free_bulk(packets_to_drop, nb_packets_to_drop);
357  }
358  }
359  }
360  }
361  free(ctx);
362 }
363 
364 /*
365  * Run on lcore 1 process_syndrome_packets() to query the bad syndrome entries
366  *
367  * @config [in]: application configuration struct
368  * @ports [in]: application ports
369  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise
370  */
373 {
374  uint16_t lcore_index = 0;
375  int current_lcore = 0;
377 
378  current_lcore = rte_get_next_lcore(current_lcore, true, false);
379 
380  ctx = (struct ipsec_security_gw_core_ctx *)malloc(sizeof(struct ipsec_security_gw_core_ctx));
381  if (ctx == NULL) {
382  DOCA_LOG_ERR("malloc() failed");
383  return DOCA_ERROR_NO_MEMORY;
384  }
385  ctx->queue_id = lcore_index;
386  ctx->config = config;
387  ctx->encrypt_rules = config->app_rules.encrypt_rules;
388  ctx->decrypt_rules = config->app_rules.decrypt_rules;
389  ctx->nb_encrypt_rules = &config->app_rules.nb_encrypt_rules;
390  ctx->ports = ports;
391 
392  if (rte_eal_remote_launch((void *)process_syndrome_packets, (void *)ctx, current_lcore) != 0) {
393  DOCA_LOG_ERR("Remote launch failed");
394  free(ctx);
395  return DOCA_ERROR_DRIVER;
396  }
397  return DOCA_SUCCESS;
398 }
399 
400 /*
401  * Run on each lcore process_queue_packets() to receive and send packets in a loop
402  *
403  * @config [in]: application configuration struct
404  * @ports [in]: application ports
405  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise
406  */
409 {
410  uint16_t lcore_index = 0;
411  int current_lcore = 0;
413  int nb_queues = config->dpdk_config->port_config.nb_queues;
414 
415  while ((current_lcore < RTE_MAX_LCORE) && (lcore_index < nb_queues)) {
416  current_lcore = rte_get_next_lcore(current_lcore, true, false);
417  ctx = (struct ipsec_security_gw_core_ctx *)malloc(sizeof(struct ipsec_security_gw_core_ctx));
418  if (ctx == NULL) {
419  DOCA_LOG_ERR("malloc() failed");
420  force_quit = true;
421  return DOCA_ERROR_NO_MEMORY;
422  }
423  ctx->queue_id = lcore_index;
424  ctx->config = config;
425  ctx->encrypt_rules = config->app_rules.encrypt_rules;
426  ctx->decrypt_rules = config->app_rules.decrypt_rules;
427  ctx->nb_encrypt_rules = &config->app_rules.nb_encrypt_rules;
428  ctx->ports = ports;
429 
430  /* Launch the worker to start process packets */
431  if (lcore_index == 0) {
432  /* lcore index 0 will not get regular packets to process */
433  if (rte_eal_remote_launch((void *)process_syndrome_packets, (void *)ctx, current_lcore) != 0) {
434  DOCA_LOG_ERR("Remote launch failed");
435  free(ctx);
436  force_quit = true;
437  return DOCA_ERROR_DRIVER;
438  }
439  } else {
440  if (rte_eal_remote_launch((void *)process_queue_packets, (void *)ctx, current_lcore) != 0) {
441  DOCA_LOG_ERR("Remote launch failed");
442  free(ctx);
443  force_quit = true;
444  return DOCA_ERROR_DRIVER;
445  }
446  }
447  lcore_index++;
448  }
449  return DOCA_SUCCESS;
450 }
451 
452 /*
453  * Unpack external buffer for new policy
454  *
455  * @buf [in]: buffer to unpack
456  * @nb_bytes [in]: buffer size
457  * @policy [out]: policy pointer to store the unpacked values
458  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise
459  */
460 static doca_error_t unpack_policy_buffer(uint8_t *buf, uint32_t nb_bytes, struct ipsec_security_gw_ipsec_policy *policy)
461 {
462  uint8_t *ptr = buf;
463 
464  policy->src_port = unpack_uint16(&ptr);
465  policy->dst_port = unpack_uint16(&ptr);
466  policy->l3_protocol = unpack_uint8(&ptr);
467  policy->l4_protocol = unpack_uint8(&ptr);
468  policy->outer_l3_protocol = unpack_uint8(&ptr);
469  policy->policy_direction = unpack_uint8(&ptr);
470  policy->policy_mode = unpack_uint8(&ptr);
471  policy->esn = unpack_uint8(&ptr);
472  policy->icv_length = unpack_uint8(&ptr);
473  policy->key_type = unpack_uint8(&ptr);
474  policy->spi = unpack_uint32(&ptr);
475  policy->salt = unpack_uint32(&ptr);
476  unpack_blob(&ptr, MAX_IP_ADDR_LEN + 1, (uint8_t *)policy->src_ip_addr);
477  policy->src_ip_addr[MAX_IP_ADDR_LEN] = '\0';
478  unpack_blob(&ptr, MAX_IP_ADDR_LEN + 1, (uint8_t *)policy->dst_ip_addr);
479  policy->dst_ip_addr[MAX_IP_ADDR_LEN] = '\0';
480  unpack_blob(&ptr, MAX_IP_ADDR_LEN + 1, (uint8_t *)policy->outer_src_ip);
481  policy->outer_src_ip[MAX_IP_ADDR_LEN] = '\0';
482  unpack_blob(&ptr, MAX_IP_ADDR_LEN + 1, (uint8_t *)policy->outer_dst_ip);
483  policy->outer_dst_ip[MAX_IP_ADDR_LEN] = '\0';
484  if (nb_bytes == POLICY_RECORD_MAX_SIZE)
485  unpack_blob(&ptr, 32, (uint8_t *)policy->enc_key_data);
486  else
487  unpack_blob(&ptr, 16, (uint8_t *)policy->enc_key_data);
488  return DOCA_SUCCESS;
489 }
490 
491 /*
492  * Read bytes_to_read from given socket
493  *
494  * @fd [in]: socket file descriptor
495  * @bytes_to_read [in]: number of bytes to read
496  * @buf [out]: store data from socket
497  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise
498  */
499 static doca_error_t fill_buffer_from_socket(int fd, size_t bytes_to_read, uint8_t *buf)
500 {
501  ssize_t ret;
502  size_t bytes_received = 0;
503 
504  do {
505  ret = recv(fd, buf + bytes_received, bytes_to_read - bytes_received, 0);
506  if (ret == -1) {
507  if (errno == EWOULDBLOCK || errno == EAGAIN)
508  return DOCA_ERROR_AGAIN;
509  else {
510  DOCA_LOG_ERR("Failed to read from socket buffer [%s]", strerror(errno));
511  return DOCA_ERROR_IO_FAILED;
512  }
513  }
514  if (ret == 0)
515  return DOCA_ERROR_AGAIN;
516  bytes_received += ret;
517  } while (bytes_received < bytes_to_read);
518 
519  return DOCA_SUCCESS;
520 }
521 
522 /*
523  * Read first 4 bytes from the socket to know policy length
524  *
525  * @app_cfg [in]: application configuration struct
526  * @length [out]: policy length
527  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise
528  */
530 {
531  uint8_t buf[8] = {0};
532  uint8_t *ptr = &buf[0];
533  uint32_t policy_length;
535 
536  result = fill_buffer_from_socket(app_cfg->socket_ctx.connfd, sizeof(uint32_t), buf);
537  if (result != DOCA_SUCCESS)
538  return result;
539 
540  policy_length = unpack_uint32(&ptr);
541  if (policy_length != POLICY_RECORD_MIN_SIZE && policy_length != POLICY_RECORD_MAX_SIZE) {
542  DOCA_LOG_ERR("Wrong policy length [%u], should be [%u] or [%u]",
543  policy_length,
546  return DOCA_ERROR_IO_FAILED;
547  }
548 
549  *length = policy_length;
550  return DOCA_SUCCESS;
551 }
552 
553 /*
554  * check if new policy where added to the socket and read it.
555  *
556  * @app_cfg [in]: application configuration struct
557  * @policy [out]: policy structure
558  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise
559  */
561  struct ipsec_security_gw_ipsec_policy *policy)
562 {
563  uint8_t buffer[1024] = {0};
564  uint32_t policy_length;
566 
567  result = read_message_length(app_cfg, &policy_length);
568  if (result != DOCA_SUCCESS)
569  return result;
570 
571  result = fill_buffer_from_socket(app_cfg->socket_ctx.connfd, policy_length, buffer);
572  if (result != DOCA_SUCCESS)
573  return result;
574 
575  return unpack_policy_buffer(buffer, policy_length, policy);
576 }
577 
578 /*
579  * Handle SW increment of SN - set the initial SN for each rule
580  *
581  * @app_cfg [in]: application configuration struct
582  * @encrypt_rules [in]: encryption rules
583  * @encrypt_array_size [in]: size of the encryption rules array
584  */
586  struct encrypt_rule *encrypt_rules,
587  int encrypt_array_size)
588 {
589  int entry_idx;
590 
591  for (entry_idx = 0; entry_idx < encrypt_array_size; entry_idx++) {
592  encrypt_rules[entry_idx].current_sn = (uint32_t)(app_cfg->sn_initial);
593  }
594 }
595 
596 /*
597  * Handle SW anti-replay - set the anti-replay state for each rule
598  *
599  * @app_cfg [in]: application configuration struct
600  * @decrypt_rules [in]: decryption rules
601  * @decrypt_array_size [in]: size of the decryption rules array
602  */
604  struct decrypt_rule *decrypt_rules,
605  int decrypt_array_size)
606 {
607  int entry_idx;
608 
609  for (entry_idx = 0; entry_idx < decrypt_array_size; entry_idx++) {
612  (uint32_t)(app_cfg->sn_initial) + SW_WINDOW_SIZE - 1;
614  }
615 }
616 
617 /*
618  * Wait in a loop and process packets until receive signal
619  *
620  * @app_cfg [in]: application configuration struct
621  * @ports [in]: application ports
622  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise
623  */
626 {
628  struct ipsec_security_gw_ipsec_policy policy = {0};
629  struct doca_flow_port *secured_port;
630  struct encrypt_rule *enc_rule;
631  struct decrypt_rule *dec_rule;
632  int encrypt_array_size, decrypt_array_size;
633 
634  DOCA_LOG_INFO("Waiting for traffic, press Ctrl+C for termination");
636  encrypt_array_size = app_cfg->socket_ctx.socket_conf ? DYN_RESERVED_RULES :
637  app_cfg->app_rules.nb_encrypt_rules;
638  decrypt_array_size = app_cfg->socket_ctx.socket_conf ? DYN_RESERVED_RULES :
639  app_cfg->app_rules.nb_decrypt_rules;
640  if (app_cfg->sw_sn_inc_enable) {
641  sw_handling_sn_inc(app_cfg, app_cfg->app_rules.encrypt_rules, encrypt_array_size);
642  }
643  if (app_cfg->sw_antireplay) {
644  /* Create and allocate an anti-replay state for each entry */
645  sw_handling_antireplay(app_cfg, app_cfg->app_rules.decrypt_rules, decrypt_array_size);
646  }
648  if (result != DOCA_SUCCESS) {
649  DOCA_LOG_ERR("Failed to process packets on all lcores");
650  goto exit_failure;
651  }
652  } else {
654  if (result != DOCA_SUCCESS) {
655  DOCA_LOG_ERR("Failed to process packets");
656  goto exit_failure;
657  }
658  }
659 
660  if (app_cfg->flow_mode == IPSEC_SECURITY_GW_VNF)
661  secured_port = ports[SECURED_IDX]->port;
662  else
663  secured_port = doca_flow_port_switch_get(NULL);
664 
665  while (!force_quit) {
666  if (!app_cfg->socket_ctx.socket_conf) {
667  sleep(1);
668  continue;
669  }
670 
671  memset(&policy, 0, sizeof(policy));
673  if (result != DOCA_SUCCESS) {
674  if (result == DOCA_ERROR_AGAIN) {
675  DOCA_LOG_DBG("No new IPsec policy, try again");
676  sleep(1);
677  continue;
678  } else {
679  DOCA_LOG_ERR("Failed to read new IPSEC policy [%s]", doca_error_get_descr(result));
680  goto exit_failure;
681  }
682  }
683 
684  print_policy_attrs(&policy);
685 
686  if (policy.policy_direction == POLICY_DIR_OUT) {
687  if (app_cfg->app_rules.nb_encrypt_rules >= MAX_NB_RULES) {
688  DOCA_LOG_ERR("Can't receive more encryption policies, maximum size is [%d]",
689  MAX_NB_RULES);
691  goto exit_failure;
692  }
693  /* Check if the array is full and reallocate memory of DYN_RESERVED_RULES blocks */
694  if ((app_cfg->app_rules.nb_encrypt_rules != 0) &&
695  (app_cfg->app_rules.nb_encrypt_rules % DYN_RESERVED_RULES == 0)) {
696  DOCA_LOG_DBG("Reallocating memory for new encryption rules");
697  app_cfg->app_rules.encrypt_rules =
698  realloc(app_cfg->app_rules.encrypt_rules,
699  (app_cfg->app_rules.nb_encrypt_rules + DYN_RESERVED_RULES) *
700  sizeof(struct encrypt_rule));
701  if (app_cfg->app_rules.encrypt_rules == NULL) {
702  DOCA_LOG_ERR("Failed to allocate memory for new encryption rule");
704  goto exit_failure;
705  }
706 
707  if (app_cfg->sw_sn_inc_enable) {
709  app_cfg->app_rules.encrypt_rules +
710  app_cfg->app_rules.nb_encrypt_rules,
712  }
713  }
714  /* Get the next empty encryption rule for egress traffic */
715  enc_rule = &app_cfg->app_rules.encrypt_rules[app_cfg->app_rules.nb_encrypt_rules];
717  if (result != DOCA_SUCCESS) {
718  DOCA_LOG_ERR("Failed to handle new encryption policy");
719  goto exit_failure;
720  }
721  } else if (policy.policy_direction == POLICY_DIR_IN) {
722  if (app_cfg->app_rules.nb_decrypt_rules >= MAX_NB_RULES) {
723  DOCA_LOG_ERR("Can't receive more decryption policies, maximum size is [%d]",
724  MAX_NB_RULES);
726  goto exit_failure;
727  }
728  /* Check if the array is full and reallocate memory of DYN_RESERVED_RULES blocks */
729  if ((app_cfg->app_rules.nb_decrypt_rules != 0) &&
730  (app_cfg->app_rules.nb_decrypt_rules % DYN_RESERVED_RULES == 0)) {
731  app_cfg->app_rules.decrypt_rules =
732  realloc(app_cfg->app_rules.decrypt_rules,
733  (app_cfg->app_rules.nb_decrypt_rules + DYN_RESERVED_RULES) *
734  sizeof(struct decrypt_rule));
735  if (app_cfg->app_rules.decrypt_rules == NULL) {
736  DOCA_LOG_ERR("Failed to allocate memory for new decryption rule");
738  goto exit_failure;
739  }
740  if (app_cfg->sw_antireplay) {
742  app_cfg->app_rules.decrypt_rules +
743  app_cfg->app_rules.nb_decrypt_rules,
745  }
746  }
747  /* Get the next empty decryption rule for ingress traffic */
748  dec_rule = &app_cfg->app_rules.decrypt_rules[app_cfg->app_rules.nb_decrypt_rules];
749  result = ipsec_security_gw_handle_decrypt_policy(app_cfg, secured_port, &policy, dec_rule);
750  if (result != DOCA_SUCCESS) {
751  DOCA_LOG_ERR("Failed to handle new decryption policy");
752  goto exit_failure;
753  }
754  }
755  }
756 
757 exit_failure:
758  force_quit = true;
759  /* If SW offload is enabled, wait till threads finish */
760  rte_eal_mp_wait_lcore();
761 
762  if (app_cfg->socket_ctx.socket_conf) {
763  /* Close the connection */
764  close(app_cfg->socket_ctx.connfd);
765  close(app_cfg->socket_ctx.fd);
766 
767  /* Remove the socket file */
768  unlink(app_cfg->socket_ctx.socket_path);
769  }
770  return result;
771 }
772 
773 /*
774  * Create socket connection, including opening new fd for socket, binding shared file, and listening for new connection
775  *
776  * @app_cfg [in/out]: application configuration structure
777  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise
778  */
780 {
781  struct sockaddr_un addr;
782  int fd, connfd = -1, flags;
784 
785  memset(&addr, 0, sizeof(addr));
786  addr.sun_family = AF_UNIX;
787 
788  strlcpy(addr.sun_path, app_cfg->socket_ctx.socket_path, MAX_SOCKET_PATH_NAME);
789 
790  /* Create a Unix domain socket */
791  fd = socket(AF_UNIX, SOCK_STREAM, 0);
792  if (fd == -1) {
793  DOCA_LOG_ERR("Failed to create new socket [%s]", strerror(errno));
794  return DOCA_ERROR_IO_FAILED;
795  }
796 
797  /* Set socket as non blocking */
798  flags = fcntl(fd, F_GETFL, 0);
799  if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
800  DOCA_LOG_ERR("Failed to set socket as non blocking [%s]", strerror(errno));
801  close(fd);
802  return DOCA_ERROR_IO_FAILED;
803  }
804 
805  /* Bind the socket to a file path */
806  if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
807  DOCA_LOG_ERR("Failed to bind the socket with the file path [%s]", strerror(errno));
809  goto exit_failure;
810  }
811 
812  /* Listen for incoming connections */
813  if (listen(fd, 5) == -1) {
814  DOCA_LOG_ERR("Failed to listen for incoming connection [%s]", strerror(errno));
816  goto exit_failure;
817  }
818 
819  DOCA_LOG_DBG("Waiting for establishing new connection");
820 
821  /* Accept an incoming connection */
822  while (!force_quit) {
823  connfd = accept(fd, NULL, NULL);
824  if (connfd == -1) {
825  if (errno == EWOULDBLOCK || errno == EAGAIN) {
826  sleep(1); /* No pending connections at the moment
827  * Wait for a short period and retry
828  */
829  continue;
830  }
831  DOCA_LOG_ERR("Failed to accept incoming connection [%s]", strerror(errno));
833  goto exit_failure;
834  } else
835  break;
836  }
837 
838  if (connfd == -1)
839  return DOCA_SUCCESS;
840 
841  /* Set socket as non blocking */
842  flags = fcntl(connfd, F_GETFL, 0);
843  if (fcntl(connfd, F_SETFL, flags | O_NONBLOCK) == -1) {
844  DOCA_LOG_ERR("Failed to set connection socket as non blocking [%s]", strerror(errno));
846  close(connfd);
847  goto exit_failure;
848  }
849  app_cfg->socket_ctx.connfd = connfd;
850  app_cfg->socket_ctx.fd = fd;
851  return DOCA_SUCCESS;
852 
853 exit_failure:
854  close(fd);
855  /* Remove the socket file */
856  unlink(app_cfg->socket_ctx.socket_path);
857  return result;
858 }
859 
860 /*
861  * Worker function to insert rules on the queues
862  *
863  * @args [in]: generic pointer to multi_thread_insertion_ctx struct
864  */
865 static void rule_inserter_worker(void *args)
866 {
869 
870  DOCA_LOG_DBG("Core %d is inserting on queue %d: %d encryption rules and %d decryption rules",
871  rte_lcore_id(),
872  ctx->queue_id,
873  ctx->nb_encrypt_rules,
874  ctx->nb_decrypt_rules);
875  if (ctx->nb_encrypt_rules > 0) {
876  result = add_encrypt_entries(ctx->app_cfg,
877  ctx->ports,
878  ctx->queue_id,
879  ctx->nb_encrypt_rules,
880  ctx->encrypt_rule_offset);
881  if (result != DOCA_SUCCESS) {
882  DOCA_LOG_ERR("Failed to add encrypt entries");
883  force_quit = true;
884  return;
885  }
886  }
887  if (ctx->nb_decrypt_rules > 0) {
888  result = add_decrypt_entries(ctx->app_cfg,
890  ctx->queue_id,
891  ctx->nb_decrypt_rules,
892  ctx->decrypt_rule_offset);
893  if (result != DOCA_SUCCESS) {
894  DOCA_LOG_ERR("Failed to add decrypt entries");
895  force_quit = true;
896  return;
897  }
898  }
899 }
900 
901 /*
902  * Check if insertion rate measure is enabled
903  *
904  * @app_cfg [in]: application configuration struct
905  * @return: true if BW perf is enabled.
906  */
908 {
909  return (app_cfg->perf_measurement == IPSEC_SECURITY_GW_PERF_INSERTION_RATE ||
910  app_cfg->perf_measurement == IPSEC_SECURITY_GW_PERF_BOTH);
911 }
912 
913 /*
914  * Run multi-thread insertion on the queues
915  *
916  * @app_cfg [in]: application configuration struct
917  * @ports [in]: application ports
918  * @nb_queues [in]: number of queues
919  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise
920  */
923  int nb_queues)
924 {
925  uint16_t lcore_index;
926  int current_lcore = 0;
927  struct multi_thread_insertion_ctx *ctxs, *ctx;
928  float encrypt_ratio, decrypt_ratio;
929  int next_encrypt_rule_offset = 0, next_decrypt_rule_offset = 0;
930  double start_time, end_time, total_time;
931  double rules_per_sec;
932  bool insertion_rate_print = is_insertion_rate(app_cfg);
933 
934  if (nb_queues < 1 || RTE_MAX_LCORE < nb_queues) {
935  DOCA_LOG_ERR("Invalid number of queues");
937  }
938 
939  if (app_cfg->app_rules.nb_encrypt_rules == 0 && app_cfg->app_rules.nb_decrypt_rules == 0) {
940  DOCA_LOG_WARN("No rules to insert");
941  return DOCA_SUCCESS;
942  }
943 
944  /* Calculate the number of queues to run - Don't create cores with less than MIN_ENTRIES_PER_CORE entries for
945  * encrypt/ decrypt */
946  nb_queues = RTE_MIN(nb_queues,
947  RTE_MAX(RTE_MAX((int)(app_cfg->app_rules.nb_encrypt_rules / MIN_ENTRIES_PER_CORE),
948  (int)(app_cfg->app_rules.nb_decrypt_rules / MIN_ENTRIES_PER_CORE)),
949  1));
950 
951  DOCA_LOG_DBG("Running multi-thread insertion on %d queues", nb_queues);
952 
953  ctxs = (struct multi_thread_insertion_ctx *)malloc(sizeof(struct multi_thread_insertion_ctx) * nb_queues);
954  if (ctxs == NULL) {
955  DOCA_LOG_ERR("malloc() failed");
956  return DOCA_ERROR_NO_MEMORY;
957  }
958  encrypt_ratio = (float)app_cfg->app_rules.nb_encrypt_rules / nb_queues;
959  decrypt_ratio = (float)app_cfg->app_rules.nb_decrypt_rules / nb_queues;
960 
961  if (insertion_rate_print)
962  start_time = rte_get_timer_cycles();
963  for (lcore_index = 0; lcore_index < nb_queues; lcore_index++) {
964  current_lcore = rte_get_next_lcore(current_lcore, true, false);
965  if (current_lcore == RTE_MAX_LCORE) {
966  DOCA_LOG_ERR("Not enough cores to run multi-thread insertion");
967  free(ctxs);
969  }
970  ctx = ctxs + lcore_index;
971 
972  ctx->app_cfg = app_cfg;
973  ctx->ports = ports;
974  ctx->queue_id = lcore_index;
975  if (encrypt_ratio < 1) { /* If the number of rules is less than the number of queues */
976  ctx->nb_encrypt_rules = lcore_index < app_cfg->app_rules.nb_encrypt_rules ? 1 : 0;
977  ctx->encrypt_rule_offset = lcore_index;
978  } else {
979  ctx->encrypt_rule_offset = next_encrypt_rule_offset;
980  next_encrypt_rule_offset = (lcore_index != (nb_queues - 1)) ?
981  (int)((lcore_index + 1) * encrypt_ratio) :
982  app_cfg->app_rules.nb_encrypt_rules;
983  ctx->nb_encrypt_rules = next_encrypt_rule_offset - ctx->encrypt_rule_offset;
984  }
985  if (decrypt_ratio < 1) { /* If the number of rules is less than the number of queues */
986  ctx->nb_decrypt_rules = lcore_index < app_cfg->app_rules.nb_decrypt_rules ? 1 : 0;
987  ctx->decrypt_rule_offset = lcore_index;
988  } else {
989  ctx->decrypt_rule_offset = next_decrypt_rule_offset;
990  next_decrypt_rule_offset = (lcore_index != (nb_queues - 1)) ?
991  (int)((lcore_index + 1) * decrypt_ratio) :
992  app_cfg->app_rules.nb_decrypt_rules;
993  ctx->nb_decrypt_rules = next_decrypt_rule_offset - ctx->decrypt_rule_offset;
994  }
995 
996  if (rte_eal_remote_launch((void *)rule_inserter_worker, (void *)ctx, current_lcore) != 0) {
997  DOCA_LOG_ERR("Remote launch failed");
998  free(ctxs);
999  return DOCA_ERROR_DRIVER;
1000  }
1001  }
1002 
1003  /* Wait for all threads to finish */
1004  rte_eal_mp_wait_lcore();
1005  if (force_quit) {
1006  DOCA_LOG_ERR("Failed to insert entries");
1007  return DOCA_ERROR_BAD_STATE;
1008  }
1009  if (insertion_rate_print) {
1010  end_time = rte_get_timer_cycles();
1011  total_time = (end_time - start_time) / rte_get_timer_hz();
1012  }
1013  DOCA_LOG_DBG("All threads finished inserting rules");
1014  if (insertion_rate_print) {
1015  DOCA_LOG_INFO("Total insertion time for %d encryption rules and %d decryption rules: %f",
1016  app_cfg->app_rules.nb_encrypt_rules,
1017  app_cfg->app_rules.nb_decrypt_rules,
1018  total_time);
1019  rules_per_sec =
1020  (app_cfg->app_rules.nb_encrypt_rules + app_cfg->app_rules.nb_decrypt_rules) / total_time;
1021  DOCA_LOG_INFO("Rules/Sec: %f", rules_per_sec);
1022  }
1023 
1024  free(ctxs);
1025  return DOCA_SUCCESS;
1026 }
1027 
1028 /*
1029  * IPsec Security Gateway application main function
1030  *
1031  * @argc [in]: command line arguments size
1032  * @argv [in]: array of command line arguments
1033  * @return: EXIT_SUCCESS on success and EXIT_FAILURE otherwise
1034  */
1035 int main(int argc, char **argv)
1036 {
1038  int ret, nb_ports = 2;
1039  int exit_status = EXIT_SUCCESS;
1041  struct ipsec_security_gw_config app_cfg = {0};
1042  struct application_dpdk_config dpdk_config = {
1044  .port_config.nb_queues = 2, /* This will be updated according to app_cfg.nb_cores in
1045  dpdk_queues_and_ports_init() */
1046  .port_config.nb_hairpin_q = 2,
1047  .port_config.enable_mbuf_metadata = true,
1048  .port_config.isolated_mode = true,
1049  .reserve_main_thread = true,
1050  };
1051  char cores_str[10];
1052  char pid_str[50]; /* Buffer for "pid_" + process ID */
1053  snprintf(pid_str, sizeof(pid_str), "pid_%d", getpid());
1054  char *eal_param[7] = {"", "-a", "00:00.0", "-l", "", "--file-prefix", pid_str};
1055  struct doca_log_backend *sdk_log;
1056 
1057  app_cfg.dpdk_config = &dpdk_config;
1058  app_cfg.nb_cores = DEFAULT_NB_CORES;
1059 
1060  /* Register a logger backend */
1062  if (result != DOCA_SUCCESS)
1063  return EXIT_FAILURE;
1064 
1065  /* Register a logger backend for internal SDK errors and warnings */
1066  result = doca_log_backend_create_with_file_sdk(stderr, &sdk_log);
1067  if (result != DOCA_SUCCESS)
1068  return EXIT_FAILURE;
1070  if (result != DOCA_SUCCESS)
1071  return EXIT_FAILURE;
1072 
1073  signal(SIGINT, signal_handler);
1074  signal(SIGTERM, signal_handler);
1075  force_quit = false;
1076 
1077  /* Init ARGP interface and start parsing cmdline/json arguments */
1079  if (result != DOCA_SUCCESS) {
1080  DOCA_LOG_ERR("Failed to init ARGP resources: %s", doca_error_get_descr(result));
1081  return EXIT_FAILURE;
1082  }
1084  if (result != DOCA_SUCCESS) {
1085  DOCA_LOG_ERR("Failed to register application params: %s", doca_error_get_descr(result));
1087  return EXIT_FAILURE;
1088  }
1089 
1090  result = doca_argp_start(argc, argv);
1091  if (result != DOCA_SUCCESS) {
1092  DOCA_LOG_ERR("Failed to parse application input: %s", doca_error_get_descr(result));
1094  return EXIT_FAILURE;
1095  }
1096 
1097  snprintf(cores_str, sizeof(cores_str), "0-%d", app_cfg.nb_cores - 1);
1098  eal_param[4] = cores_str;
1099  ret = rte_eal_init(7, eal_param);
1100  if (ret < 0) {
1101  DOCA_LOG_ERR("EAL initialization failed");
1103  return EXIT_FAILURE;
1104  }
1105 
1107  if (result != DOCA_SUCCESS) {
1108  DOCA_LOG_ERR("Failed to parse application json file: %s", doca_error_get_descr(result));
1109  exit_status = EXIT_FAILURE;
1110  goto dpdk_destroy;
1111  }
1112 
1113  if (app_cfg.flow_mode == IPSEC_SECURITY_GW_SWITCH)
1114  dpdk_config.port_config.self_hairpin = true;
1115 
1117  if (result != DOCA_SUCCESS) {
1118  DOCA_LOG_ERR("Failed to open DOCA devices: %s", doca_error_get_descr(result));
1119  exit_status = EXIT_FAILURE;
1120  goto config_destroy;
1121  }
1122 
1123  /* Update queues and ports */
1124  result = dpdk_queues_and_ports_init(&dpdk_config);
1125  if (result != DOCA_SUCCESS) {
1126  DOCA_LOG_ERR("Failed to update application ports and queues: %s", doca_error_get_descr(result));
1127  exit_status = EXIT_FAILURE;
1128  goto device_cleanup;
1129  }
1130 
1132  if (result != DOCA_SUCCESS) {
1133  DOCA_LOG_ERR("Failed to init DOCA Flow");
1134  exit_status = EXIT_FAILURE;
1135  goto dpdk_cleanup;
1136  }
1137 
1138  result = doca_devinfo_get_mac_addr(doca_dev_as_devinfo((app_cfg.objects.secured_dev.doca_dev)),
1139  ports[SECURED_IDX]->eth_header.src_mac,
1141  if (result != DOCA_SUCCESS) {
1142  DOCA_LOG_WARN("Failed to get mac address from DOCA device, setting mac address to default");
1143  SET_MAC_ADDR(ports[SECURED_IDX]->eth_header.src_mac, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66);
1144  }
1145 
1146  if (app_cfg.flow_mode == IPSEC_SECURITY_GW_SWITCH) {
1147  DOCA_LOG_WARN("switch mode can not set real source mac, setting mac address to default");
1148  SET_MAC_ADDR(ports[UNSECURED_IDX]->eth_header.src_mac, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66);
1149  }
1150 
1151  else {
1152  result = doca_devinfo_get_mac_addr(doca_dev_as_devinfo((app_cfg.objects.unsecured_dev.doca_dev)),
1153  ports[UNSECURED_IDX]->eth_header.src_mac,
1155  if (result != DOCA_SUCCESS) {
1156  DOCA_LOG_WARN("Failed to get mac address from DOCA device, setting mac address to default");
1157  SET_MAC_ADDR(ports[UNSECURED_IDX]->eth_header.src_mac, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66);
1158  }
1159  }
1160 
1162  if (result != DOCA_SUCCESS) {
1163  DOCA_LOG_ERR("Failed to init status entries");
1164  exit_status = EXIT_FAILURE;
1165  goto doca_flow_cleanup;
1166  }
1167 
1168  if (app_cfg.flow_mode == IPSEC_SECURITY_GW_SWITCH) {
1170  ports[SECURED_IDX]->port,
1171  dpdk_config.port_config.nb_queues,
1172  &app_cfg.switch_pipes.rss_pipe.pipe);
1173  if (result != DOCA_SUCCESS) {
1174  DOCA_LOG_ERR("Failed to create encrypt egress pipes");
1175  exit_status = EXIT_FAILURE;
1176  goto doca_flow_cleanup;
1177  }
1178  }
1179 
1181  if (result != DOCA_SUCCESS) {
1182  DOCA_LOG_ERR("Failed to bind encrypt and decrypt rules");
1183  exit_status = EXIT_FAILURE;
1184  goto doca_flow_cleanup;
1185  }
1186 
1188  if (result != DOCA_SUCCESS) {
1189  DOCA_LOG_ERR("Failed to create encrypt egress pipes");
1190  exit_status = EXIT_FAILURE;
1191  goto doca_flow_cleanup;
1192  }
1193 
1194  if (app_cfg.flow_mode == IPSEC_SECURITY_GW_SWITCH) {
1196  if (result != DOCA_SUCCESS) {
1197  DOCA_LOG_ERR("Failed to create switch root pipe");
1198  exit_status = EXIT_FAILURE;
1199  goto doca_flow_cleanup;
1200  }
1201  }
1202 
1204  if (result != DOCA_SUCCESS) {
1205  DOCA_LOG_ERR("Failed to create encrypt rules");
1206  exit_status = EXIT_FAILURE;
1207  goto doca_flow_cleanup;
1208  }
1209 
1211  if (result != DOCA_SUCCESS) {
1212  DOCA_LOG_ERR("Failed to create decrypt rules");
1213  exit_status = EXIT_FAILURE;
1214  goto doca_flow_cleanup;
1215  }
1216 
1217  if (app_cfg.flow_mode == IPSEC_SECURITY_GW_SWITCH) {
1219  if (result != DOCA_SUCCESS) {
1220  DOCA_LOG_ERR("Failed to create switch root pipe");
1221  exit_status = EXIT_FAILURE;
1222  goto doca_flow_cleanup;
1223  }
1224  }
1225 
1226  if (!app_cfg.socket_ctx.socket_conf) {
1227  result = run_multithread_insertion(&app_cfg, ports, app_cfg.dpdk_config->port_config.nb_queues);
1228  if (result != DOCA_SUCCESS) {
1229  DOCA_LOG_ERR("Failed to run multi-thread insertion");
1230  exit_status = EXIT_FAILURE;
1231  goto doca_flow_cleanup;
1232  }
1233  } else {
1234  app_cfg.app_rules.nb_encrypt_rules = 0;
1235  app_cfg.app_rules.nb_decrypt_rules = 0;
1237  if (result != DOCA_SUCCESS) {
1238  DOCA_LOG_ERR("Failed to create policy socket");
1239  exit_status = EXIT_FAILURE;
1240  goto doca_flow_cleanup;
1241  }
1242  }
1243 
1245  if (result != DOCA_SUCCESS) {
1246  DOCA_LOG_ERR("Error happened during waiting for new traffic");
1247  exit_status = EXIT_FAILURE;
1248  goto doca_flow_cleanup;
1249  }
1250 
1253  /* Flow cleanup */
1257 dpdk_cleanup:
1258  /* DPDK cleanup */
1259  dpdk_queues_and_ports_fini(&dpdk_config);
1260 device_cleanup:
1262 config_destroy:
1263  if (app_cfg.app_rules.encrypt_rules)
1264  free(app_cfg.app_rules.encrypt_rules);
1265  if (app_cfg.app_rules.decrypt_rules)
1266  free(app_cfg.app_rules.decrypt_rules);
1267 dpdk_destroy:
1268  dpdk_fini();
1269  /* ARGP cleanup */
1271  return exit_status;
1272 }
#define NULL
Definition: __stddef_null.h:26
int32_t result
void doca_flow_cleanup(int nb_ports, struct ipsec_security_gw_ports_map *ports[])
Definition: flow_common.c:360
doca_error_t create_rss_pipe(struct ipsec_security_gw_config *app_cfg, struct doca_flow_port *port, uint16_t nb_queues, struct doca_flow_pipe **rss_pipe)
Definition: flow_common.c:384
doca_error_t ipsec_security_gw_init_status(struct ipsec_security_gw_config *app_cfg, int nb_queues)
Definition: flow_common.c:315
doca_error_t create_switch_ingress_root_pipes(struct ipsec_security_gw_ports_map *ports[], struct ipsec_security_gw_config *app_cfg)
Definition: flow_common.c:815
void security_gateway_free_status_entries(struct ipsec_security_gw_config *app_cfg)
Definition: flow_common.c:954
doca_error_t ipsec_security_gw_bind(struct ipsec_security_gw_ports_map *ports[], struct ipsec_security_gw_config *app_cfg)
Definition: flow_common.c:333
void security_gateway_free_resources(struct ipsec_security_gw_config *app_cfg)
Definition: flow_common.c:960
doca_error_t ipsec_security_gw_init_doca_flow(const struct ipsec_security_gw_config *app_cfg, int nb_queues, struct ipsec_security_gw_ports_map *ports[])
Definition: flow_common.c:163
doca_error_t create_switch_egress_root_pipes(struct ipsec_security_gw_ports_map *ports[], struct ipsec_security_gw_config *app_cfg)
Definition: flow_common.c:840
uint32_t encrypt
Definition: flow_common.h:2
#define SECURED_IDX
Definition: flow_common.h:40
#define UNSECURED_IDX
Definition: flow_common.h:41
#define SET_MAC_ADDR(addr, a, b, c, d, e, f)
Definition: flow_common.h:60
doca_error_t register_ipsec_security_gw_params(void)
Definition: config.c:1578
doca_error_t ipsec_security_gw_parse_config(struct ipsec_security_gw_config *app_cfg)
Definition: config.c:1236
uintptr_t addr
void dpdk_fini(void)
Definition: dpdk_utils.c:919
doca_error_t dpdk_queues_and_ports_init(struct application_dpdk_config *app_dpdk_config)
Definition: dpdk_utils.c:515
void dpdk_queues_and_ports_fini(struct application_dpdk_config *app_dpdk_config)
Definition: dpdk_utils.c:564
doca_error_t ipsec_security_gw_insert_decrypt_rules(struct ipsec_security_gw_ports_map *ports[], struct ipsec_security_gw_config *app_cfg)
doca_error_t handle_secured_packets_received(struct rte_mbuf **packet, bool bad_syndrome_check, struct ipsec_security_gw_core_ctx *ctx)
doca_error_t add_decrypt_entries(struct ipsec_security_gw_config *app_cfg, struct ipsec_security_gw_ports_map *port, uint16_t queue_id, int nb_rules, int rule_offset)
doca_error_t ipsec_security_gw_create_encrypt_egress(struct ipsec_security_gw_ports_map *ports[], struct ipsec_security_gw_config *app_cfg)
doca_error_t ipsec_security_gw_insert_encrypt_rules(struct ipsec_security_gw_ports_map *ports[], struct ipsec_security_gw_config *app_cfg)
doca_error_t add_encrypt_entries(struct ipsec_security_gw_config *app_cfg, struct ipsec_security_gw_ports_map *ports[], uint16_t queue_id, int nb_rules, int rule_offset)
doca_error_t handle_unsecured_packets_received(struct rte_mbuf **packet, struct ipsec_security_gw_core_ctx *ctx)
static uint8_t entry_idx
static struct app_gpu_cfg app_cfg
DOCA_EXPERIMENTAL doca_error_t doca_argp_start(int argc, char **argv)
Parse incoming arguments (cmd line/json).
DOCA_EXPERIMENTAL doca_error_t doca_argp_init(const char *program_name, void *program_config)
Initialize the parser interface.
DOCA_EXPERIMENTAL doca_error_t doca_argp_destroy(void)
ARG Parser destroy.
DOCA_STABLE doca_error_t doca_devinfo_get_mac_addr(const struct doca_devinfo *devinfo, uint8_t *mac_addr, uint32_t size)
Get the MAC address of a DOCA devinfo.
DOCA_STABLE struct doca_devinfo * doca_dev_as_devinfo(const struct doca_dev *dev)
Get local device info from device. This should be useful when wanting to query information about devi...
enum doca_error doca_error_t
DOCA API return codes.
DOCA_STABLE const char * doca_error_get_descr(doca_error_t error)
Returns the description string of an error code.
@ DOCA_ERROR_INVALID_VALUE
Definition: doca_error.h:44
@ DOCA_ERROR_BAD_STATE
Definition: doca_error.h:56
@ DOCA_ERROR_IO_FAILED
Definition: doca_error.h:55
@ DOCA_ERROR_AGAIN
Definition: doca_error.h:43
@ DOCA_SUCCESS
Definition: doca_error.h:38
@ DOCA_ERROR_NO_MEMORY
Definition: doca_error.h:45
@ DOCA_ERROR_DRIVER
Definition: doca_error.h:59
DOCA_EXPERIMENTAL int doca_flow_crypto_ipsec_resource_handle(struct doca_flow_port *port, uint64_t quota, uint32_t max_processed_resources)
Handle ipsec resources.
@ DOCA_FLOW_L3_TYPE_IP4
DOCA_EXPERIMENTAL void doca_flow_tune_server_destroy(void)
Destroy the DOCA Flow Tune Server.
DOCA_STABLE struct doca_flow_port * doca_flow_port_switch_get(const struct doca_flow_port *port)
Get doca flow switch port.
DOCA_EXPERIMENTAL doca_error_t doca_flow_resource_query_entry(struct doca_flow_pipe_entry *entry, struct doca_flow_resource_query *query_stats)
Extract information about specific entry.
DOCA_EXPERIMENTAL doca_error_t doca_log_backend_create_standard(void)
Create default, non configurable backend for application messages.
#define DOCA_LOG_ERR(format,...)
Generates an ERROR application log message.
Definition: doca_log.h:466
#define DOCA_LOG_WARN(format,...)
Generates a WARNING application log message.
Definition: doca_log.h:476
#define DOCA_LOG_INFO(format,...)
Generates an INFO application log message.
Definition: doca_log.h:486
#define DOCA_LOG_TRC(format,...)
Generates a TRACE application log message.
Definition: doca_log.h:513
DOCA_EXPERIMENTAL doca_error_t doca_log_backend_create_with_file_sdk(FILE *fptr, struct doca_log_backend **backend)
Create a logging backend with a FILE* stream for SDK messages.
#define DOCA_LOG_DBG(format,...)
Generates a DEBUG application log message.
Definition: doca_log.h:496
DOCA_EXPERIMENTAL doca_error_t doca_log_backend_set_sdk_level(struct doca_log_backend *backend, uint32_t level)
Set the log level limit for SDK logging backends.
@ DOCA_LOG_LEVEL_WARNING
Definition: doca_log.h:47
doca_error_t ipsec_security_gw_init_devices(struct ipsec_security_gw_config *app_cfg)
Definition: ipsec_ctx.c:221
doca_error_t ipsec_security_gw_close_devices(const struct ipsec_security_gw_config *app_cfg)
Definition: ipsec_ctx.c:170
#define SW_WINDOW_SIZE
Definition: ipsec_ctx.h:44
@ IPSEC_SECURITY_GW_FWD_SYNDROME_RSS
Definition: ipsec_ctx.h:210
#define MAX_NB_RULES
Definition: ipsec_ctx.h:40
#define NUM_OF_SYNDROMES
Definition: ipsec_ctx.h:43
@ IPSEC_SECURITY_GW_VNF
Definition: ipsec_ctx.h:187
@ IPSEC_SECURITY_GW_SWITCH
Definition: ipsec_ctx.h:188
@ IPSEC_SECURITY_GW_ESP_OFFLOAD_BOTH
Definition: ipsec_ctx.h:193
#define DYN_RESERVED_RULES
Definition: ipsec_ctx.h:41
@ IPSEC_SECURITY_GW_PERF_BOTH
Definition: ipsec_ctx.h:204
@ IPSEC_SECURITY_GW_PERF_INSERTION_RATE
Definition: ipsec_ctx.h:202
#define MAX_SOCKET_PATH_NAME
Definition: ipsec_ctx.h:38
static bool query_pipe_info(struct security_gateway_pipe_info *pipe)
static void sw_handling_antireplay(struct ipsec_security_gw_config *app_cfg, struct decrypt_rule *decrypt_rules, int decrypt_array_size)
static char * syndrome_list[NUM_OF_SYNDROMES]
static void process_queue_packets(void *args)
static doca_error_t ipsec_security_gw_process_bad_packets(struct ipsec_security_gw_config *config, struct ipsec_security_gw_ports_map *ports[])
static doca_error_t ipsec_security_gw_wait_for_traffic(struct ipsec_security_gw_config *app_cfg, struct ipsec_security_gw_ports_map *ports[])
int main(int argc, char **argv)
static doca_error_t unpack_policy_buffer(uint8_t *buf, uint32_t nb_bytes, struct ipsec_security_gw_ipsec_policy *policy)
static doca_error_t run_multithread_insertion(struct ipsec_security_gw_config *app_cfg, struct ipsec_security_gw_ports_map *ports[], int nb_queues)
#define PACKET_BURST
static doca_error_t create_policy_socket(struct ipsec_security_gw_config *app_cfg)
#define DEFAULT_NB_CORES
static void rule_inserter_worker(void *args)
static bool is_fwd_syndrome_rss(struct ipsec_security_gw_config *app_cfg)
#define MAC_ADDRESS_SIZE
#define NB_TX_BURST_TRIES
DOCA_LOG_REGISTER(IPSEC_SECURITY_GW)
static doca_error_t ipsec_security_gw_process_packets(struct ipsec_security_gw_config *config, struct ipsec_security_gw_ports_map *ports[])
static doca_error_t read_message_length(struct ipsec_security_gw_config *app_cfg, uint32_t *length)
static doca_error_t fill_buffer_from_socket(int fd, size_t bytes_to_read, uint8_t *buf)
static void process_syndrome_packets(void *args)
static bool force_quit
static void query_decrypt_pipes(struct ipsec_security_gw_config *app_cfg)
static void handle_packets_received(uint16_t port_id, uint16_t nb_packets, struct rte_mbuf **packets, struct ipsec_security_gw_core_ctx *ctx, uint16_t *nb_processed_packets, struct rte_mbuf **processed_packets, struct rte_mbuf **unprocessed_packets)
static bool is_insertion_rate(struct ipsec_security_gw_config *app_cfg)
#define MIN_ENTRIES_PER_CORE
static void query_bad_syndrome(struct decrypt_rule *decrypt_rule)
static void sw_handling_sn_inc(struct ipsec_security_gw_config *app_cfg, struct encrypt_rule *encrypt_rules, int encrypt_array_size)
static void query_encrypt_pipes(struct ipsec_security_gw_config *app_cfg)
static doca_error_t read_message_from_socket(struct ipsec_security_gw_config *app_cfg, struct ipsec_security_gw_ipsec_policy *policy)
static void signal_handler(int signum)
void unpack_blob(uint8_t **buffer, size_t length, uint8_t *output)
Definition: pack.c:152
uint16_t unpack_uint16(uint8_t **buffer)
Definition: pack.c:108
uint8_t unpack_uint8(uint8_t **buffer)
Definition: pack.c:99
uint32_t unpack_uint32(uint8_t **buffer)
Definition: pack.c:120
doca_error_t ipsec_security_gw_handle_decrypt_policy(struct ipsec_security_gw_config *app_cfg, struct doca_flow_port *secured_port, struct ipsec_security_gw_ipsec_policy *policy, struct decrypt_rule *rule)
Definition: policy.c:269
void print_policy_attrs(struct ipsec_security_gw_ipsec_policy *policy)
Definition: policy.c:296
doca_error_t ipsec_security_gw_handle_encrypt_policy(struct ipsec_security_gw_config *app_cfg, struct ipsec_security_gw_ports_map *ports[], struct ipsec_security_gw_ipsec_policy *policy, struct encrypt_rule *rule)
Definition: policy.c:244
#define POLICY_RECORD_MAX_SIZE
Definition: policy.h:120
#define POLICY_DIR_IN
Definition: policy.h:109
#define POLICY_DIR_OUT
Definition: policy.h:110
#define MAX_IP_ADDR_LEN
Definition: policy.h:108
#define POLICY_RECORD_MIN_SIZE
Definition: policy.h:119
uint64_t bitmap
Definition: ipsec_ctx.h:69
uint32_t window_size
Definition: ipsec_ctx.h:67
uint32_t end_win_sn
Definition: ipsec_ctx.h:68
struct application_port_config port_config
Definition: dpdk_utils.h:70
uint32_t previous_stats
Definition: ipsec_ctx.h:62
struct doca_flow_pipe_entry * entry
Definition: ipsec_ctx.h:61
doca_be32_t dst_ip6[4]
Definition: ipsec_ctx.h:84
doca_be32_t esp_spi
Definition: ipsec_ctx.h:86
doca_be32_t dst_ip4
Definition: ipsec_ctx.h:83
enum doca_flow_l3_type l3_type
Definition: ipsec_ctx.h:81
struct antireplay_state antireplay_state
Definition: ipsec_ctx.h:90
struct bad_syndrome_entry entries[NUM_OF_SYNDROMES]
Definition: ipsec_ctx.h:89
flow resource query
Definition: doca_flow.h:1101
struct doca_flow_resource_query::@115::@117 counter
uint32_t current_sn
Definition: ipsec_ctx.h:121
struct ipsec_security_gw_rules app_rules
Definition: ipsec_ctx.h:256
struct application_dpdk_config * dpdk_config
Definition: ipsec_ctx.h:252
struct ipsec_security_gw_config * config
Definition: flow_common.h:87
struct decrypt_rule * decrypt_rules
Definition: flow_common.h:89
struct encrypt_rule * encrypt_rules
Definition: flow_common.h:88
char dst_ip_addr[MAX_IP_ADDR_LEN+1]
Definition: policy.h:145
uint8_t enc_key_data[MAX_KEY_LEN]
Definition: policy.h:141
char outer_dst_ip[MAX_IP_ADDR_LEN+1]
Definition: policy.h:147
char outer_src_ip[MAX_IP_ADDR_LEN+1]
Definition: policy.h:146
char src_ip_addr[MAX_IP_ADDR_LEN+1]
Definition: policy.h:144
struct decrypt_rule * decrypt_rules
Definition: ipsec_ctx.h:170
struct encrypt_rule * encrypt_rules
Definition: ipsec_ctx.h:169
struct ipsec_security_gw_config * app_cfg
struct ipsec_security_gw_ports_map ** ports
char name[MAX_NAME_LEN+1]
Definition: ipsec_ctx.h:74
struct doca_flow_pipe_entry * entry
Definition: ipsec_ctx.h:75
uint32_t prev_stats
Definition: ipsec_ctx.h:76
char name[MAX_NAME_LEN+1]
Definition: ipsec_ctx.h:127
struct security_gateway_entry_info * entries_info
Definition: ipsec_ctx.h:130
struct doca_flow_port * ports[UPF_ACCEL_PORTS_MAX]
Definition: upf_accel.h:344
static int nb_ports
Definition: switch_core.c:44
static struct doca_flow_port * ports[FLOW_SWITCH_PORTS_MAX]
Definition: switch_core.c:42
struct upf_accel_ctx * ctx
size_t strlcpy(char *dst, const char *src, size_t size)
Definition: utils.c:123