Commit a589b6d7 authored by Joanne Hugé's avatar Joanne Hugé

Clean up and enforce ecpri_period parameter

parent c4fba315
......@@ -9,3 +9,6 @@ raw-socket-test/raw_socket
raw-socket-test/raw_socket.d
raw-socket-test/raw_socket.o
dpdk-test/build
*.so
*.o
*.d
......@@ -3,7 +3,7 @@
CC=gcc -m64 -msse4.1
CXX=g++ -m64 -msse4.1
CFLAGS=-fno-strict-aliasing -Wall -pedantic
CFLAGS=-O2 -fno-strict-aliasing -Wall -pedantic
CFLAGS+=-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
CFLAGS +=-DALLOW_EXPERIMENTAL_API
CFLAGS+=-MMD -g
......@@ -32,7 +32,9 @@ LDFLAGS = -l:libpthread.a -l:libm.a
all: $(LIB)
$(LIB): $(APP).o
$(CC) -shared $(LDFLAGS) $(LDFLAGS_STATIC) -o $@ $<
$(CC) -shared -o $@ $< -lm -lpthread $(LDFLAGS_SHARED)
#$(LIB): $(APP).o
# $(CC) -shared $(LDFLAGS) $(LDFLAGS_STATIC) -o $@ $<
%.o: %.c
$(CC) $(CFLAGS) $(SRCS-y) -fpic -c -o $@
......
......@@ -8,7 +8,7 @@ CFLAGS +=-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
CFLAGS += -DALLOW_EXPERIMENTAL_API
CXXFLAGS=$(CFLAGS)
LIB=trx_ecpri_dpdk
LIBDIR=/root/ecpri/trx-ecpri-priv
LIBDIR=/root/ecpri-priv
LDFLAGS=-l$(LIB)
PROG=test-dpdk-ecpri
......@@ -16,7 +16,7 @@ PROG=test-dpdk-ecpri
all: $(PROG)
$(PROG): $(PROG).o
$(CC) -o $@ $< $(LDFLAGS)
$(CC) -L$(LIBDIR) -o $@ $< $(LDFLAGS)
%.o: %.c
$(CC) $(CFLAGS) -c -o $@ $<
......
......@@ -85,16 +85,11 @@ int main(int argc, char * argv[]) {
s = malloc(sizeof(TRXEcpriState));
memset(s, 0, sizeof(*s));
#if 1
s->rec_mac = "b8:59:9f:07:7d:da";
s->rec_mac = "b8:59:9f:07:86:42";
s->re_mac = "04:09:a5:0f:9f:4c";
s->rec_if = "ens9f0np0";
#else
s->rec_mac = "b8:ce:f6:4b:00:22";
s->re_mac = "b8:ce:f6:4b:00:23";
s->rec_if = "ens5f0np0";
#endif
s->rec_if = "ens9f0";
s->recv_affinity = 39;
s->send_affinity = 38;
s->prepare_affinity = 37;
......@@ -109,7 +104,7 @@ int main(int argc, char * argv[]) {
startdpdk(s);
for(int i = 0; i < 1000; i++) {
for(;;) {
sleep(1);
}
......
......@@ -4,4 +4,5 @@ cd ..;
make;
cd ecpri-tests;
make all;
export LD_LIBRARY_PATH="/root/ecpri-priv:$LD_LIBRARY_PATH"
./test-dpdk-ecpri
chrt -f 97 taskset -c 39 phc2sys -m -c ens9f1 -s CLOCK_REALTIME -O0 -f $HOME/linuxptp/configs/G.8275.1.cfg
chrt -f 97 taskset -c 39 phc2sys -m -c ens5f0 -s CLOCK_REALTIME -O0 -f $HOME/linuxptp/configs/G.8275.1.cfg
chrt -f 97 taskset -c 38 ptp4l -H -i ens9f1 -m -f $HOME/linuxptp/configs/G.8275.1.cfg
chrt -f 97 taskset -c 38 ptp4l -H -i ens5f0 -m -f $HOME/linuxptp/configs/G.8275.1.cfg
......@@ -61,7 +61,7 @@
static void log_error(const char * section, const char * msg, ...) {
time_t t;
struct tm ts;
char line[256];
char line[256];
va_list arglist;
time(&t);
......@@ -78,7 +78,7 @@ static void log_error(const char * section, const char * msg, ...) {
static void log_info(const char * section, const char * msg, ...) {
time_t t;
struct tm ts;
char line[256];
char line[256];
va_list arglist;
time(&t);
......@@ -95,7 +95,7 @@ static void log_info(const char * section, const char * msg, ...) {
static void log_debug(const char * section, const char * msg, ...) {
time_t t;
struct tm ts;
char line[256];
char line[256];
va_list arglist;
time(&t);
......@@ -148,7 +148,7 @@ void set_latency_target(void) {
err = write(latency_target_fd, &latency_target_value, 4);
if (err < 1) {
error(EXIT_FAILURE, errno, "# error setting cpu_dma_latency to %d!",
latency_target_value);
latency_target_value);
close(latency_target_fd);
return;
}
......@@ -170,6 +170,7 @@ typedef struct {
const char * re_mac;
const char * rec_mac;
const char * rec_if;
const char * dpdk_options;
int recv_affinity;
int send_affinity;
int prepare_affinity;
......@@ -217,7 +218,7 @@ static struct timespec int_to_ts(int64_t t) {
return ts;
}
static int64_t ts_to_int(struct timespec ts) {
return ts.tv_sec * NSEC_PER_SEC + ts.tv_nsec;
return ts.tv_sec * NSEC_PER_SEC + ts.tv_nsec;
}
static void add_ns(struct timespec *t, int64_t ns) {
t->tv_nsec += ns;
......@@ -269,61 +270,61 @@ struct rte_ether_addr s_addr;
struct rte_ether_addr d_addr;
int8_t data[BURST_SIZE][DATA_SIZE];
static const struct rte_eth_conf port_conf_default = {
.rxmode = { .max_rx_pkt_len = RTE_ETHER_MAX_LEN }
.rxmode = { .max_lro_pkt_size = RTE_ETHER_MAX_LEN }
};
static inline int port_init(int portid, struct rte_mempool *mbuf_pool) {
struct rte_eth_conf port_conf = port_conf_default;
const uint16_t rx_rings = 1, tx_rings = 1;
int retval;
uint16_t q;
retval = rte_eth_dev_configure(portid, rx_rings, tx_rings, &port_conf);
if (retval != 0)
return retval;
/* Allocate and set up 1 RX queue per Ethernet port. */
for (q = 0; q < rx_rings; q++) {
retval = rte_eth_rx_queue_setup(portid, q, nb_rxd,
rte_eth_dev_socket_id(portid), NULL, mbuf_pool);
if (retval < 0)
return retval;
}
/* Allocate and set up 1 TX queue per Ethernet port. */
for (q = 0; q < tx_rings; q++) {
retval = rte_eth_tx_queue_setup(portid, q, nb_txd,
rte_eth_dev_socket_id(portid), NULL);
if (retval < 0)
return retval;
}
/* Start the Ethernet port. */
retval = rte_eth_dev_start(portid);
if (retval < 0)
return retval;
return 0;
struct rte_eth_conf port_conf = port_conf_default;
const uint16_t rx_rings = 1, tx_rings = 1;
int retval;
uint16_t q;
retval = rte_eth_dev_configure(portid, rx_rings, tx_rings, &port_conf);
if (retval != 0)
return retval;
/* Allocate and set up 1 RX queue per Ethernet port. */
for (q = 0; q < rx_rings; q++) {
retval = rte_eth_rx_queue_setup(portid, q, nb_rxd,
rte_eth_dev_socket_id(portid), NULL, mbuf_pool);
if (retval < 0)
return retval;
}
/* Allocate and set up 1 TX queue per Ethernet port. */
for (q = 0; q < tx_rings; q++) {
retval = rte_eth_tx_queue_setup(portid, q, nb_txd,
rte_eth_dev_socket_id(portid), NULL);
if (retval < 0)
return retval;
}
/* Start the Ethernet port. */
retval = rte_eth_dev_start(portid);
if (retval < 0)
return retval;
return 0;
}
static void init_dpdk(int argc, char ** argv) {
unsigned int nb_mbufs;
int ret;
ret = rte_eal_init(argc, argv);
if (ret < 0)
rte_exit(EXIT_FAILURE, "initlize fail!");
ret = rte_eal_init(argc, argv);
if (ret < 0)
rte_exit(EXIT_FAILURE, "initlize fail!");
argc -= ret;
argv += ret;
argc -= ret;
argv += ret;
nb_mbufs = RTE_MAX((nb_rxd + nb_txd + BURST_SIZE + MEMPOOL_CACHE_SIZE), 8192U);
mbuf_pool = rte_pktmbuf_pool_create("MBUF_POOL", nb_mbufs,
MEMPOOL_CACHE_SIZE, 0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());
if (mbuf_pool == NULL)
rte_exit(EXIT_FAILURE, "Cannot create mbuf pool\n");
mbuf_pool = rte_pktmbuf_pool_create("MBUF_POOL", nb_mbufs,
MEMPOOL_CACHE_SIZE, 0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());
if (mbuf_pool == NULL)
rte_exit(EXIT_FAILURE, "Cannot create mbuf pool\n");
if (port_init(0, mbuf_pool) != 0)
rte_exit(EXIT_FAILURE, "Cannot init port %"PRIu8 "\n", 0);
if (port_init(0, mbuf_pool) != 0)
rte_exit(EXIT_FAILURE, "Cannot init port %"PRIu8 "\n", 0);
}
static void send_packets(int port) {
struct rte_mbuf * pkt[BURST_SIZE];
......@@ -335,15 +336,16 @@ static void send_packets(int port) {
pkt[i] = rte_pktmbuf_alloc(mbuf_pool);
eth_hdr = rte_pktmbuf_mtod(pkt[i], struct rte_ether_hdr*);
if(port) {
eth_hdr->d_addr = s_addr;
eth_hdr->s_addr = d_addr;
eth_hdr->dst_addr = s_addr;
eth_hdr->src_addr = d_addr;
} else {
eth_hdr->d_addr = d_addr;
eth_hdr->s_addr = s_addr;
eth_hdr->dst_addr = d_addr;
eth_hdr->src_addr = s_addr;
}
eth_hdr->ether_type = htons(0xaefe);
memcpy(rte_pktmbuf_mtod_offset(pkt[i], uint8_t *, sizeof(struct rte_ether_hdr)), data[i], DATA_SIZE);
pkt_size = DATA_SIZE + sizeof(struct rte_ether_hdr);
//pkt_size = DATA_SIZE + sizeof(struct rte_ether_hdr);
pkt_size = PACKET_SIZE;
pkt[i]->data_len = pkt_size;
pkt[i]->pkt_len = pkt_size;
}
......@@ -356,38 +358,38 @@ static void send_packets(int port) {
uint16_t buf;
for (buf = nb_tx; buf < BURST_SIZE; buf++)
rte_pktmbuf_free(pkt[buf]);
fprintf(stderr, "Sent %d packets instead of %d\n", nb_tx, BURST_SIZE);
exit(EXIT_FAILURE);
fprintf(stderr, "Sent %d packets instead of %d\n", nb_tx, BURST_SIZE);
exit(EXIT_FAILURE);
}
}
// TODO store received packets' data in buffer
static int recv_packets(int port) {
struct rte_mbuf * pkt[BURST_SIZE];
while(1) {
const int nb_rx = rte_eth_rx_burst(port, 0, pkt, BURST_SIZE);
while(1) {
const int nb_rx = rte_eth_rx_burst(port, 0, pkt, 1024);
for(int i = 0; i < nb_rx; i++)
rte_pktmbuf_free(pkt[i]);
if(nb_rx)
if(nb_rx)
return nb_rx;
}
}
}
/* DPDK */
static void *recv_thread(void *p) {
cpu_set_t mask;
cpu_set_t mask;
TRXEcpriState * s = (TRXEcpriState *) p;
log_info("RECV_THREAD", "Thread init");
// Set thread CPU affinity
CPU_ZERO(&mask);
CPU_SET(s->recv_affinity, &mask);
if (sched_setaffinity(0, sizeof(mask), &mask))
error(EXIT_FAILURE, errno, "Could not set CPU affinity to CPU %d\n", s->recv_affinity);
// Set thread CPU affinity
CPU_ZERO(&mask);
CPU_SET(s->recv_affinity, &mask);
if (sched_setaffinity(0, sizeof(mask), &mask))
error(EXIT_FAILURE, errno, "Could not set CPU affinity to CPU %d\n", s->recv_affinity);
for(;;) {
......@@ -407,16 +409,16 @@ static void *recv_thread(void *p) {
static void *send_thread(void *p) {
cpu_set_t mask;
cpu_set_t mask;
struct timespec initial, next;
TRXEcpriState * s = (TRXEcpriState *) p;
log_info("SEND_THREAD", "Thread init");
// Set thread CPU affinity
CPU_ZERO(&mask);
CPU_SET(s->send_affinity, &mask);
if (sched_setaffinity(0, sizeof(mask), &mask))
error(EXIT_FAILURE, errno, "Could not set CPU affinity to CPU %d\n", s->send_affinity);
// Set thread CPU affinity
CPU_ZERO(&mask);
CPU_SET(s->send_affinity, &mask);
if (sched_setaffinity(0, sizeof(mask), &mask))
error(EXIT_FAILURE, errno, "Could not set CPU affinity to CPU %d\n", s->send_affinity);
pthread_mutex_lock(&tx_ready_mutex);
pthread_cond_wait(&tx_ready_cond, &tx_ready_mutex);
......@@ -462,16 +464,16 @@ static void *send_thread(void *p) {
static void *prepare_thread(void *p) {
cpu_set_t mask;
cpu_set_t mask;
TRXEcpriState * s = (TRXEcpriState *) p;
int tx_ready_buffer_full = 0;
log_info("PREPARE_THREAD", "Thread init");
// Set thread CPU affinity
CPU_ZERO(&mask);
CPU_SET(s->prepare_affinity, &mask);
if (sched_setaffinity(0, sizeof(mask), &mask))
error(EXIT_FAILURE, errno, "Could not set CPU affinity to CPU %d\n", s->prepare_affinity);
// Set thread CPU affinity
CPU_ZERO(&mask);
CPU_SET(s->prepare_affinity, &mask);
if (sched_setaffinity(0, sizeof(mask), &mask))
error(EXIT_FAILURE, errno, "Could not set CPU affinity to CPU %d\n", s->prepare_affinity);
for(int64_t i = 0;; i++) {
int16_t samples_int[N_SAMPLES];
......@@ -519,7 +521,7 @@ static void *prepare_thread(void *p) {
}
}
else {
*((uint16_t *) (RBUF_WRITE(tx_rbuf, uint8_t) + 20)) = htons(seq_id++);
*((uint16_t *) (RBUF_WRITE(tx_rbuf, uint8_t) + 6)) = htons(seq_id++);
rbuf_update_write_index(&tx_rbuf);
prepared_frame_count++;
}
......@@ -540,17 +542,17 @@ static void *prepare_thread(void *p) {
}
static void *decompress_thread(void *p) {
cpu_set_t mask;
cpu_set_t mask;
TRXEcpriState * s = (TRXEcpriState *) p;
int rx_ready = 0;
const float mult = 1. / 32767.;
log_info("DECOMPRESS_THREAD", "Thread init");
// Set thread CPU affinity
CPU_ZERO(&mask);
CPU_SET(s->decompress_affinity, &mask);
if (sched_setaffinity(0, sizeof(mask), &mask))
error(EXIT_FAILURE, errno, "Could not set CPU affinity to CPU %d\n", s->decompress_affinity);
// Set thread CPU affinity
CPU_ZERO(&mask);
CPU_SET(s->decompress_affinity, &mask);
if (sched_setaffinity(0, sizeof(mask), &mask))
error(EXIT_FAILURE, errno, "Could not set CPU affinity to CPU %d\n", s->decompress_affinity);
for(;;) {
int n = rbuf_read_amount(&rx_rbuf);
......@@ -585,30 +587,43 @@ static void *decompress_thread(void *p) {
}
static void *statistic_thread(void *p) {
struct timespec next, initial, current;
cpu_set_t mask;
cpu_set_t mask;
int64_t duration_ns;
TRXEcpriState * s = (TRXEcpriState *) p;
const int div_a[] = {1,2,4,5,8,10,16,20,25,32,40,50,64,80,100,125,128,160,200,250,256,320,400,500,512,625,640,800,1000,1250,1280,1600,2000,2500,2560,3125,3200,4000,5000,6250,6400,8000,10000,12500,12800,15625,16000,20000,25000,31250};
const int div_b[] = {1000000000,500000000,250000000,200000000,125000000,100000000,62500000,50000000,40000000,31250000,25000000,20000000,15625000,12500000,10000000,8000000,7812500,6250000,5000000,4000000,3906250,3125000,2500000,2000000,1953125,1600000,1562500,1250000,1000000,800000,781250,625000,500000,400000,390625,320000,312500,250000,200000,160000,156250,125000,100000,80000,78125,64000,62500,50000,40000,32000};
int div_index = 0;
int div_indexr = 0;
log_info("STATISTIC_THREAD", "Thread init");
// Set thread CPU affinity
CPU_ZERO(&mask);
CPU_SET(s->statistic_affinity, &mask);
if (sched_setaffinity(0, sizeof(mask), &mask))
error(EXIT_FAILURE, errno, "Could not set CPU affinity to CPU %d\n", s->statistic_affinity);
// Set thread CPU affinity
CPU_ZERO(&mask);
CPU_SET(s->statistic_affinity, &mask);
if (sched_setaffinity(0, sizeof(mask), &mask))
error(EXIT_FAILURE, errno, "Could not set CPU affinity to CPU %d\n", s->statistic_affinity);
clock_gettime(CLOCK_TAI, &initial);
next = initial;
for(;;) {
int64_t pps, ppsr;
add_ns(&next, STATISTIC_REFRESH_RATE);
clock_gettime(CLOCK_TAI, &current);
duration_ns = calcdiff_ns(current, initial);
log_info("STATS", "%14" PRIi64 " - %14" PRIi64 " - %14" PRIi64 " - %14" PRIi64 " - %14" PRIi64 "pps",
prepared_frame_count,
read_frame_count,
sent_frame_count,
recv_frame_count,
(NSEC_PER_SEC * sent_frame_count) / duration_ns);
if(sent_frame_count >= INT64_MAX / div_b[div_index])
div_index++;
if(recv_frame_count >= INT64_MAX / div_b[div_indexr])
div_indexr++;
pps = ((sent_frame_count * div_b[div_index]) / duration_ns) * div_a[div_index];
ppsr = ((recv_frame_count * div_b[div_indexr]) / duration_ns) * div_a[div_indexr];
log_info("STATS", "%14" PRIi64 " - %14" PRIi64 " - %14" PRIi64 " - %14" PRIi64 " - %14" PRIi64 "pps %14" PRIi64 "pps",
prepared_frame_count,
read_frame_count,
sent_frame_count,
recv_frame_count,
pps,
ppsr);
clock_nanosleep(CLOCK_TAI, TIMER_ABSTIME, &next, NULL);
}
pthread_exit(EXIT_SUCCESS);
......@@ -714,41 +729,36 @@ static int start_threads(TRXEcpriState * s) {
int startdpdk(TRXEcpriState * s) {
uint8_t ecpri_message[DATA_SIZE];
#define USE10G
#define ARGC 11
#define ARGC_LEN 256
char _argv[ARGC][ARGC_LEN] = {
"",
"-l",
"28",
"-b",
"0000:04:00.0",
#ifdef USE10G
"-b",
"0000:3b:00.0",
#endif
"-b",
"0000:3b:00.1",
#ifndef USE10G
"-b",
"0000:5e:00.0",
#endif
"-b",
"0000:5e:00.1",
};
char ** argv = (char **) malloc(sizeof(char *) * ARGC);
for(int i = 0; i < ARGC; i++) {
argv[i] = (char *) malloc(ARGC_LEN);
strcpy(argv[i], _argv[i]);
int argc = 0;
int k = 0;
int prev_space = 0;
char ** argv;
for(int i = 0;; i++)
if(s->dpdk_options[i] == ' ')
argc++;
else if(s->dpdk_options[i] == '\0')
break;
argv = (char **) malloc(sizeof(char *) * argc);
for(int i = 0;; i++) {
if(s->dpdk_options[i] == ' ') {
argv[k] = (char *) malloc(i - prev_space + 1);
strncpy(argv[k], s->dpdk_options, i - prev_space);
argv[k][i - prev_space] = '\0';
prev_space = i;
k++;
}
else if(s->dpdk_options[i] == '\0') {
break;
}
}
init_dpdk(ARGC, argv);
#undef ARGC
#undef ARGC_LEN
init_dpdk(argc, argv);
log_debug("TRX_ECPRI", "start");
//set_latency_target();
//set_latency_target();
seq_id = 0;
read_frame_count = 0;
......@@ -777,22 +787,22 @@ int startdpdk(TRXEcpriState * s) {
memset((uint8_t *) ecpri_message, 0, DATA_SIZE);
if(sscanf(s->re_mac, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx%*c",
&d_addr.addr_bytes[0],
&d_addr.addr_bytes[1],
&d_addr.addr_bytes[2],
&d_addr.addr_bytes[3],
&d_addr.addr_bytes[4],
&d_addr.addr_bytes[5]) != 6)
&d_addr.addr_bytes[0],
&d_addr.addr_bytes[1],
&d_addr.addr_bytes[2],
&d_addr.addr_bytes[3],
&d_addr.addr_bytes[4],
&d_addr.addr_bytes[5]) != 6)
fprintf(stderr, "Invalid eRE MAC address\n");
if(sscanf(s->rec_mac, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx%*c",
&s_addr.addr_bytes[0],
&s_addr.addr_bytes[1],
&s_addr.addr_bytes[2],
&s_addr.addr_bytes[3],
&s_addr.addr_bytes[4],
&s_addr.addr_bytes[5]) != 6)
&s_addr.addr_bytes[0],
&s_addr.addr_bytes[1],
&s_addr.addr_bytes[2],
&s_addr.addr_bytes[3],
&s_addr.addr_bytes[4],
&s_addr.addr_bytes[5]) != 6)
fprintf(stderr, "Invalid eREC MAC address\n");
/* Standard Header */
ecpri_message[0] = 0x10; // Protocol data revision 0x1, C = 0
// Message type = 0x00, IQ data
......@@ -858,7 +868,7 @@ static int trx_ecpri_read(TRXState *s1, trx_timestamp_t *ptimestamp, void **__sa
rate. Here we don't implement it, so the user has to force a given
sample rate with the "sample_rate" configuration option */
static int trx_ecpri_get_sample_rate(TRXState *s1, TRXFraction *psample_rate,
int *psample_rate_num, int sample_rate_min)
int *psample_rate_num, int sample_rate_min)
{
return -1;
}
......@@ -867,6 +877,8 @@ static int trx_ecpri_start(TRXState *s1, const TRXDriverParams *params)
{
TRXEcpriState *s = s1->opaque;
log_debug("TRX_ECPRI_START", "Start");
s->sample_rate = params->sample_rate[0].num / params->sample_rate[0].den;
startdpdk(s);
......@@ -888,9 +900,9 @@ int trx_driver_init(TRXState *s1)
log_info("TRX_ECPRI", "Init");
if (s1->trx_api_version != TRX_API_VERSION) {
fprintf(stderr, "ABI compatibility mismatch between LTEENB and TRX driver (LTEENB ABI version=%d, TRX driver ABI version=%d)\n",
s1->trx_api_version, TRX_API_VERSION);
return -1;
fprintf(stderr, "ABI compatibility mismatch between LTEENB and TRX driver (LTEENB ABI version=%d, TRX driver ABI version=%d)\n",
s1->trx_api_version, TRX_API_VERSION);
return -1;
}
s = malloc(sizeof(TRXEcpriState));
......@@ -909,11 +921,16 @@ int trx_driver_init(TRXState *s1)
trx_get_param_double(s1, &val, "flow_id");
s->flow_id = (int) val;
trx_get_param_double(s1, &val, "ecpri_period");
if(((int) val) == 0) {
fprintf(stderr, "ecpri_period parameter can't be null\n");
return -1;
}
s->ecpri_period = (int) val;
s->re_mac = trx_get_param_string(s1, "re_mac");
s->rec_mac = trx_get_param_string(s1, "rec_mac");
s->rec_if = trx_get_param_string(s1, "rec_if");
s->dpdk_options = trx_get_param_string(s1, "dpdk_options");
s1->opaque = s;
s1->trx_end_func = trx_ecpri_end;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment