+
+// only called once
+// Returns:
+//
+// 1 on success;
+//
+// 0 if "the EAL cannot initialize on this system", which we treat as
+// meaning "DPDK isn't available";
+//
+// a PCAP_ERROR_ code for other errors.
+//
+// If eaccess_not_fatal is non-zero, treat "a permissions issue" the way
+// we treat "the EAL cannot initialize on this system". We use that
+// when trying to find DPDK devices, as we don't want to fail to return
+// *any* devices just because we can't support DPDK; when we're trying
+// to open a device, we need to return a permissions error in that case.
+static int dpdk_pre_init(char * ebuf, int eaccess_not_fatal)
+{
+ int dargv_cnt=0;
+ char *dargv[DPDK_ARGC_MAX];
+ char *ptr_dpdk_cfg = NULL;
+ int ret;
+ // global var
+ if (is_dpdk_pre_inited != 0)
+ {
+ // already inited; did that succeed?
+ if (is_dpdk_pre_inited < 0)
+ {
+ // failed
+ goto error;
+ }
+ else
+ {
+ // succeeded
+ return 1;
+ }
+ }
+ // init EAL
+ ptr_dpdk_cfg = getenv(DPDK_CFG_ENV_NAME);
+ // set default log level to debug
+ rte_log_set_global_level(DPDK_DEF_LOG_LEV);
+ if (ptr_dpdk_cfg == NULL)
+ {
+ RTE_LOG(INFO,USER1,"env $DPDK_CFG is unset, so using default: %s\n",DPDK_DEF_CFG);
+ ptr_dpdk_cfg = DPDK_DEF_CFG;
+ }
+ memset(dpdk_cfg_buf,0,sizeof(dpdk_cfg_buf));
+ snprintf(dpdk_cfg_buf,DPDK_CFG_MAX_LEN-1,"%s %s",DPDK_LIB_NAME,ptr_dpdk_cfg);
+ dargv_cnt = parse_dpdk_cfg(dpdk_cfg_buf,dargv);
+ ret = rte_eal_init(dargv_cnt,dargv);
+ if (ret == -1)
+ {
+ // Indicate that we've called rte_eal_init() by setting
+ // is_dpdk_pre_inited to the negative of the error code,
+ // and process the error.
+ is_dpdk_pre_inited = -rte_errno;
+ goto error;
+ }
+ // init succeeded, so we do not need to do it again later.
+ is_dpdk_pre_inited = 1;
+ return 1;
+
+error:
+ switch (-is_dpdk_pre_inited)
+ {
+ case EACCES:
+ // This "indicates a permissions issue.".
+ RTE_LOG(ERR, USER1, "%s\n", DPDK_ERR_PERM_MSG);
+ // If we were told to treat this as just meaning
+ // DPDK isn't available, do so.
+ if (eaccess_not_fatal)
+ return 0;
+ // Otherwise report a fatal error.
+ snprintf(ebuf, PCAP_ERRBUF_SIZE,
+ "DPDK requires that it run as root");
+ return PCAP_ERROR_PERM_DENIED;
+
+ case EAGAIN:
+ // This "indicates either a bus or system
+ // resource was not available, setup may
+ // be attempted again."
+ // There's no such error in pcap, so I'm
+ // not sure what we should do here.
+ snprintf(ebuf, PCAP_ERRBUF_SIZE,
+ "Bus or system resource was not available");
+ break;
+
+ case EALREADY:
+ // This "indicates that the rte_eal_init
+ // function has already been called, and
+ // cannot be called again."
+ // That's not an error; set the "we've
+ // been here before" flag and return
+ // success.
+ is_dpdk_pre_inited = 1;
+ return 1;
+
+ case EFAULT:
+ // This "indicates the tailq configuration
+ // name was not found in memory configuration."
+ snprintf(ebuf, PCAP_ERRBUF_SIZE,
+ "The tailq configuration name was not found in the memory configuration");
+ return PCAP_ERROR;
+
+ case EINVAL:
+ // This "indicates invalid parameters were
+ // passed as argv/argc." Those came from
+ // the configuration file.
+ snprintf(ebuf, PCAP_ERRBUF_SIZE,
+ "The configuration file has invalid parameters");
+ break;
+
+ case ENOMEM:
+ // This "indicates failure likely caused by
+ // an out-of-memory condition."
+ snprintf(ebuf, PCAP_ERRBUF_SIZE,
+ "Out of memory");
+ break;
+
+ case ENODEV:
+ // This "indicates memory setup issues."
+ snprintf(ebuf, PCAP_ERRBUF_SIZE,
+ "An error occurred setting up memory");
+ break;
+
+ case ENOTSUP:
+ // This "indicates that the EAL cannot
+ // initialize on this system." We treat
+ // that as meaning DPDK isn't available
+ // on this machine, rather than as a
+ // fatal error, and let our caller decide
+ // whether that's a fatal error (if trying
+ // to activate a DPDK device) or not (if
+ // trying to enumerate devices).
+ return 0;
+
+ case EPROTO:
+ // This "indicates that the PCI bus is
+ // either not present, or is not readable
+ // by the eal." Does "the PCI bus is not
+ // present" mean "this machine has no PCI
+ // bus", which strikes me as a "not available"
+ // case? If so, should "is not readable by
+ // the EAL" also something we should treat
+ // as a "not available" case? If not, we
+ // can't distinguish between the two, so
+ // we're stuck.
+ snprintf(ebuf, PCAP_ERRBUF_SIZE,
+ "PCI bus is not present or not readable by the EAL");
+ break;
+
+ case ENOEXEC:
+ // This "indicates that a service core
+ // failed to launch successfully."
+ snprintf(ebuf, PCAP_ERRBUF_SIZE,
+ "A service core failed to launch successfully");
+ break;
+
+ default:
+ //
+ // That's not in the list of errors in
+ // the documentation; let it be reported
+ // as an error.
+ //
+ dpdk_fmt_errmsg_for_rte_errno(ebuf,
+ PCAP_ERRBUF_SIZE, -is_dpdk_pre_inited,
+ "dpdk error: dpdk_pre_init failed");
+ break;
+ }
+ // Error.
+ return PCAP_ERROR;
+}
+