@@ -294,8 +294,6 @@ static void *gen_send_thread(void *arg)
odp_pktio_t pktio;
thread_args_t *thr_args;
odp_queue_t outq_def;
- odp_pktio_params_t params;
- socket_params_t *sock_params = ¶ms.sock_params;
odp_buffer_t buf;
@@ -303,8 +301,7 @@ static void *gen_send_thread(void *arg)
thr_args = arg;
/* Open a packet IO instance for this thread */
- sock_params->type = 1;
- pktio = odp_pktio_open(thr_args->pktio_dev, thr_args->pool, ¶ms);
+ pktio = odp_pktio_open(thr_args->pktio_dev, thr_args->pool);
if (pktio == ODP_PKTIO_INVALID) {
ODP_ERR(" [%02i] Error: pktio create failed\n", thr);
return NULL;
@@ -454,10 +451,8 @@ static void *gen_recv_thread(void *arg)
odp_pktio_t pktio;
thread_args_t *thr_args;
odp_queue_t inq_def;
- odp_pktio_params_t params;
char inq_name[ODP_QUEUE_NAME_LEN];
odp_queue_param_t qparam;
- socket_params_t *sock_params = ¶ms.sock_params;
odp_packet_t pkt;
odp_buffer_t buf;
@@ -466,8 +461,7 @@ static void *gen_recv_thread(void *arg)
thr_args = arg;
/* Open a packet IO instance for this thread */
- sock_params->type = 1;
- pktio = odp_pktio_open(thr_args->pktio_dev, thr_args->pool, ¶ms);
+ pktio = odp_pktio_open(thr_args->pktio_dev, thr_args->pool);
if (pktio == ODP_PKTIO_INVALID) {
ODP_ERR(" [%02i] Error: pktio create failed\n", thr);
return NULL;
@@ -901,6 +895,10 @@ static void usage(char *progname)
"\n"
"Optional OPTIONS\n"
" -h, --help Display help and exit.\n"
+ " environment variables: ODP_PKTIO_DISABLE_SOCKET_MMAP\n"
+ " ODP_PKTIO_DISABLE_SOCKET_MMSG\n"
+ " ODP_PKTIO_DISABLE_SOCKET_BASIC\n"
+ " can be used to advanced pkt I/O selection for linux-generic\n"
"\n", NO_PATH(progname), NO_PATH(progname)
);
}
@@ -52,8 +52,6 @@ typedef struct {
int core_count;
int if_count; /**< Number of interfaces to be used */
char **if_names; /**< Array of pointers to interface names */
- int type; /**< Packet IO type */
- int fanout; /**< Packet IO fanout */
crypto_api_mode_e mode; /**< Crypto API preferred mode */
odp_buffer_pool_t pool; /**< Buffer pool for packet IO */
} appl_args_t;
@@ -540,11 +538,9 @@ void initialize_loop(char *intf)
* forwarding database.
*
* @param intf Interface name string
- * @param type Packet IO type (BASIC, MMSG, MMAP)
- * @param fanout Packet IO fanout
*/
static
-void initialize_intf(char *intf, int type, int fanout)
+void initialize_intf(char *intf)
{
odp_pktio_t pktio;
odp_queue_t outq_def;
@@ -552,17 +548,13 @@ void initialize_intf(char *intf, int type, int fanout)
char inq_name[ODP_QUEUE_NAME_LEN];
odp_queue_param_t qparam;
int ret;
- odp_pktio_params_t params;
- socket_params_t *sock_params = ¶ms.sock_params;
uint8_t src_mac[ODPH_ETHADDR_LEN];
char src_mac_str[MAX_STRING];
/*
* Open a packet IO instance for thread and get default output queue
*/
- sock_params->type = type;
- sock_params->fanout = fanout;
- pktio = odp_pktio_open(intf, pkt_pool, ¶ms);
+ pktio = odp_pktio_open(intf, pkt_pool);
if (ODP_PKTIO_INVALID == pktio) {
ODP_ERR("Error: pktio create failed for %s\n", intf);
exit(EXIT_FAILURE);
@@ -1292,9 +1284,7 @@ main(int argc, char *argv[])
if (!strncmp("loop", args->appl.if_names[i], strlen("loop")))
initialize_loop(args->appl.if_names[i]);
else
- initialize_intf(args->appl.if_names[i],
- args->appl.type,
- args->appl.fanout);
+ initialize_intf(args->appl.if_names[i]);
}
/* If we have test streams build them before starting workers */
@@ -1373,12 +1363,10 @@ static void parse_args(int argc, char *argv[], appl_args_t *appl_args)
printf("\nParsing command line options\n");
- appl_args->type = 3; /* 3: ODP_PKTIO_TYPE_SOCKET_MMAP */
- appl_args->fanout = 0; /* turn off fanout by default for mmap */
appl_args->mode = 0; /* turn off async crypto API by default */
while (!rc) {
- opt = getopt_long(argc, argv, "+c:i:m:t:f:h:r:p:a:e:s:",
+ opt = getopt_long(argc, argv, "+c:i:m:h:r:p:a:e:s:",
longopts, &long_index);
if (-1 == opt)
@@ -1431,14 +1419,6 @@ static void parse_args(int argc, char *argv[], appl_args_t *appl_args)
}
break;
- case 't':
- appl_args->type = atoi(optarg);
- break;
-
- case 'f':
- appl_args->fanout = atoi(optarg);
- break;
-
case 'm':
appl_args->mode = atoi(optarg);
break;
@@ -1536,12 +1516,6 @@ static void usage(char *progname)
"\n"
"Mandatory OPTIONS:\n"
" -i, --interface Eth interfaces (comma-separated, no spaces)\n"
- " -t, --type 1: ODP_PKTIO_TYPE_SOCKET_BASIC\n"
- " 2: ODP_PKTIO_TYPE_SOCKET_MMSG\n"
- " 3: ODP_PKTIO_TYPE_SOCKET_MMAP\n"
- " 4: ODP_PKTIO_TYPE_NETMAP\n"
- " Default: 3: ODP_PKTIO_TYPE_SOCKET_MMAP\n"
- " -f, --fanout 0: off 1: on (Default 1: on)\n"
" -m, --mode 0: SYNC\n"
" 1: ASYNC_IN_PLACE\n"
" 2: ASYNC_NEW_BUFFER\n"
@@ -1568,6 +1542,10 @@ static void usage(char *progname)
"Optional OPTIONS\n"
" -c, --count <number> Core count.\n"
" -h, --help Display help and exit.\n"
+ " environment variables: ODP_PKTIO_DISABLE_SOCKET_MMAP\n"
+ " ODP_PKTIO_DISABLE_SOCKET_MMSG\n"
+ " ODP_PKTIO_DISABLE_SOCKET_BASIC\n"
+ " can be used to advanced pkt I/O selection for linux-generic\n"
"\n", NO_PATH(progname), NO_PATH(progname)
);
}
@@ -122,15 +122,11 @@ static void usage(char *progname);
static odp_pktio_t burst_mode_init_params(void *arg, odp_buffer_pool_t pool)
{
thread_args_t *args;
- odp_pktio_params_t params;
- socket_params_t *sock_params = ¶ms.sock_params;
odp_pktio_t pktio;
args = arg;
/* Open a packet IO instance for this thread */
- sock_params->type = args->type;
- sock_params->fanout = args->fanout;
- pktio = odp_pktio_open(args->srcif, pool, ¶ms);
+ pktio = odp_pktio_open(args->srcif, pool);
if (pktio == ODP_PKTIO_INVALID)
ODP_ERR(" Error: pktio create failed");
@@ -417,8 +413,6 @@ int main(int argc, char *argv[])
gbl_args->thread[i].dstif = gbl_args->appl.if_names[if_idx-1];
gbl_args->thread[i].pool = pool;
gbl_args->thread[i].mode = gbl_args->appl.mode;
- gbl_args->thread[i].type = gbl_args->appl.type;
- gbl_args->thread[i].fanout = gbl_args->appl.fanout;
if (gbl_args->appl.mode == APPL_MODE_PKT_BURST) {
pktio = burst_mode_init_params(&gbl_args->thread[i], pool);
@@ -518,11 +512,9 @@ static void parse_args(int argc, char *argv[], appl_args_t *appl_args)
};
appl_args->mode = -1; /* Invalid, must be changed by parsing */
- appl_args->type = 3; /* 3: ODP_PKTIO_TYPE_SOCKET_MMAP */
- appl_args->fanout = 1; /* turn off fanout by default for mmap */
while (1) {
- opt = getopt_long(argc, argv, "+c:i:m:t:f:h",
+ opt = getopt_long(argc, argv, "+c:i:m:h",
longopts, &long_index);
if (opt == -1)
@@ -583,14 +575,6 @@ static void parse_args(int argc, char *argv[], appl_args_t *appl_args)
appl_args->mode = APPL_MODE_PKT_QUEUE;
break;
- case 't':
- appl_args->type = atoi(optarg);
- break;
-
- case 'f':
- appl_args->fanout = atoi(optarg);
- break;
-
case 'h':
usage(argv[0]);
exit(EXIT_SUCCESS);
@@ -663,16 +647,14 @@ static void usage(char *progname)
" -i, --interface Eth interfaces (comma-separated, no spaces)\n"
" -m, --mode 0: Burst send&receive packets (no queues)\n"
" 1: Send&receive packets through ODP queues.\n"
- " -t, --type 1: ODP_PKTIO_TYPE_SOCKET_BASIC\n"
- " 2: ODP_PKTIO_TYPE_SOCKET_MMSG\n"
- " 3: ODP_PKTIO_TYPE_SOCKET_MMAP\n"
- " 4: ODP_PKTIO_TYPE_NETMAP\n"
- " Default: 3: ODP_PKTIO_TYPE_SOCKET_MMAP\n"
- " -f, --fanout 0: off 1: on (Default 1: on)\n"
"\n"
"Optional OPTIONS\n"
" -c, --count <number> Core count.\n"
" -h, --help Display help and exit.\n\n"
+ " environment variables: ODP_PKTIO_DISABLE_SOCKET_MMAP\n"
+ " ODP_PKTIO_DISABLE_SOCKET_MMSG\n"
+ " ODP_PKTIO_DISABLE_SOCKET_BASIC\n"
+ " can be used to advanced pkt I/O selection for linux-generic\n"
"\n", NO_PATH(progname), NO_PATH(progname)
);
}
@@ -68,8 +68,6 @@ typedef struct {
int if_count; /**< Number of interfaces to be used */
char **if_names; /**< Array of pointers to interface names */
int mode; /**< Packet IO mode */
- int type; /**< Packet IO type */
- int fanout; /**< Packet IO fanout */
odp_buffer_pool_t pool; /**< Buffer pool for packet IO */
} appl_args_t;
@@ -80,8 +78,6 @@ typedef struct {
char *pktio_dev; /**< Interface name to use */
odp_buffer_pool_t pool; /**< Buffer pool for packet IO */
int mode; /**< Thread mode */
- int type; /**< Thread i/o type */
- int fanout; /**< Thread i/o fanout */
} thread_args_t;
/**
@@ -124,8 +120,6 @@ static void *pktio_queue_thread(void *arg)
int ret;
unsigned long pkt_cnt = 0;
unsigned long err_cnt = 0;
- odp_pktio_params_t params;
- socket_params_t *sock_params = ¶ms.sock_params;
thr = odp_thread_id();
thr_args = arg;
@@ -141,9 +135,7 @@ static void *pktio_queue_thread(void *arg)
}
/* Open a packet IO instance for this thread */
- sock_params->type = thr_args->type;
- sock_params->fanout = thr_args->fanout;
- pktio = odp_pktio_open(thr_args->pktio_dev, pkt_pool, ¶ms);
+ pktio = odp_pktio_open(thr_args->pktio_dev, pkt_pool);
if (pktio == ODP_PKTIO_INVALID) {
ODP_ERR(" [%02i] Error: pktio create failed\n", thr);
return NULL;
@@ -212,7 +204,7 @@ static void *pktio_queue_thread(void *arg)
odp_queue_enq(outq_def, buf);
/* Print packet counts every once in a while */
- if (odp_unlikely(pkt_cnt++ % 100000 == 0)) {
+ if (odp_unlikely(pkt_cnt++ % 1 == 0)) {
printf(" [%02i] pkt_cnt:%lu\n", thr, pkt_cnt);
fflush(NULL);
}
@@ -237,8 +229,6 @@ static void *pktio_ifburst_thread(void *arg)
unsigned long pkt_cnt = 0;
unsigned long err_cnt = 0;
unsigned long tmp = 0;
- odp_pktio_params_t params;
- socket_params_t *sock_params = ¶ms.sock_params;
thr = odp_thread_id();
thr_args = arg;
@@ -254,9 +244,7 @@ static void *pktio_ifburst_thread(void *arg)
}
/* Open a packet IO instance for this thread */
- sock_params->type = thr_args->type;
- sock_params->fanout = thr_args->fanout;
- pktio = odp_pktio_open(thr_args->pktio_dev, pkt_pool, ¶ms);
+ pktio = odp_pktio_open(thr_args->pktio_dev, pkt_pool);
if (pktio == ODP_PKTIO_INVALID) {
ODP_ERR(" [%02i] Error: pktio create failed.\n", thr);
return NULL;
@@ -283,7 +271,7 @@ static void *pktio_ifburst_thread(void *arg)
/* Print packet counts every once in a while */
tmp += pkts_ok;
- if (odp_unlikely((tmp >= 100000) || /* OR first print:*/
+ if (odp_unlikely((tmp >= 1) || /* OR first print:*/
((pkt_cnt == 0) && ((tmp-1) < MAX_PKT_BURST)))) {
pkt_cnt += tmp;
printf(" [%02i] pkt_cnt:%lu\n", thr, pkt_cnt);
@@ -395,8 +383,6 @@ int main(int argc, char *argv[])
args->thread[i].pktio_dev = args->appl.if_names[if_idx];
args->thread[i].pool = pool;
args->thread[i].mode = args->appl.mode;
- args->thread[i].type = args->appl.type;
- args->thread[i].fanout = args->appl.fanout;
if (args->appl.mode == APPL_MODE_PKT_BURST)
thr_run_func = pktio_ifburst_thread;
@@ -510,11 +496,9 @@ static void parse_args(int argc, char *argv[], appl_args_t *appl_args)
};
appl_args->mode = -1; /* Invalid, must be changed by parsing */
- appl_args->type = 3; /* 3: ODP_PKTIO_TYPE_SOCKET_MMAP */
- appl_args->fanout = 1; /* turn off fanout by default for mmap */
while (1) {
- opt = getopt_long(argc, argv, "+c:i:m:t:f:h",
+ opt = getopt_long(argc, argv, "+c:i:m:h",
longopts, &long_index);
if (opt == -1)
@@ -575,14 +559,6 @@ static void parse_args(int argc, char *argv[], appl_args_t *appl_args)
appl_args->mode = APPL_MODE_PKT_QUEUE;
break;
- case 't':
- appl_args->type = atoi(optarg);
- break;
-
- case 'f':
- appl_args->fanout = atoi(optarg);
- break;
-
case 'h':
usage(argv[0]);
exit(EXIT_SUCCESS);
@@ -652,16 +628,14 @@ static void usage(char *progname)
" -i, --interface Eth interfaces (comma-separated, no spaces)\n"
" -m, --mode 0: Burst send&receive packets (no queues)\n"
" 1: Send&receive packets through ODP queues.\n"
- " -t, --type 1: ODP_PKTIO_TYPE_SOCKET_BASIC\n"
- " 2: ODP_PKTIO_TYPE_SOCKET_MMSG\n"
- " 3: ODP_PKTIO_TYPE_SOCKET_MMAP\n"
- " 4: ODP_PKTIO_TYPE_NETMAP\n"
- " Default: 3: ODP_PKTIO_TYPE_SOCKET_MMAP\n"
- " -f, --fanout 0: off 1: on (Default 1: on)\n"
"\n"
"Optional OPTIONS\n"
" -c, --count <number> Core count.\n"
" -h, --help Display help and exit.\n"
+ " environment variables: ODP_PKTIO_DISABLE_SOCKET_MMAP\n"
+ " ODP_PKTIO_DISABLE_SOCKET_MMSG\n"
+ " ODP_PKTIO_DISABLE_SOCKET_BASIC\n"
+ " can be used to advanced pkt I/O selection for linux-generic\n"
"\n", NO_PATH(progname), NO_PATH(progname)
);
}
@@ -36,12 +36,10 @@ typedef uint32_t odp_pktio_t;
*
* @param dev Packet IO device
* @param pool Pool to use for packet IO
- * @param params Set of parameters to pass to the arch dependent implementation
*
* @return ODP packet IO handle or ODP_PKTIO_INVALID on error
*/
-odp_pktio_t odp_pktio_open(const char *dev, odp_buffer_pool_t pool,
- odp_pktio_params_t *params);
+odp_pktio_t odp_pktio_open(const char *dev, odp_buffer_pool_t pool);
/**
* Close an ODP packet IO instance
@@ -20,9 +20,6 @@ extern "C" {
#include <odp_spinlock.h>
#include <odp_packet_socket.h>
-#ifdef ODP_HAVE_NETMAP
-#include <odp_packet_netmap.h>
-#endif
struct pktio_entry {
odp_spinlock_t lock; /**< entry spinlock */
@@ -32,9 +29,6 @@ struct pktio_entry {
odp_pktio_params_t params; /**< pktio parameters */
pkt_sock_t pkt_sock; /**< using socket API for IO */
pkt_sock_mmap_t pkt_sock_mmap; /**< using socket mmap API for IO */
-#ifdef ODP_HAVE_NETMAP
- pkt_netmap_t pkt_nm; /**< using netmap API for IO */
-#endif
};
typedef union {
@@ -109,32 +109,16 @@ static void unlock_entry(pktio_entry_t *entry)
odp_spinlock_unlock(&entry->s.lock);
}
-static void init_pktio_entry(pktio_entry_t *entry, odp_pktio_params_t *params)
+static void init_pktio_entry(pktio_entry_t *entry)
{
set_taken(entry);
entry->s.inq_default = ODP_QUEUE_INVALID;
- switch (params->type) {
- case ODP_PKTIO_TYPE_SOCKET_BASIC:
- case ODP_PKTIO_TYPE_SOCKET_MMSG:
- case ODP_PKTIO_TYPE_SOCKET_MMAP:
- memset(&entry->s.pkt_sock, 0, sizeof(entry->s.pkt_sock));
- memset(&entry->s.pkt_sock_mmap, 0,
- sizeof(entry->s.pkt_sock_mmap));
- break;
-#ifdef ODP_HAVE_NETMAP
- case ODP_PKTIO_TYPE_NETMAP:
- memset(&entry->s.pkt_nm, 0, sizeof(entry->s.pkt_nm));
- break;
-#endif
- default:
- ODP_ERR("Packet I/O type not supported. Please recompile\n");
- break;
- }
- /* Save pktio parameters, type is the most useful */
- memcpy(&entry->s.params, params, sizeof(*params));
+ memset(&entry->s.params, 0, sizeof(entry->s.params));
+ memset(&entry->s.pkt_sock, 0, sizeof(entry->s.pkt_sock));
+ memset(&entry->s.pkt_sock_mmap, 0, sizeof(entry->s.pkt_sock_mmap));
}
-static odp_pktio_t alloc_lock_pktio_entry(odp_pktio_params_t *params)
+static odp_pktio_t alloc_lock_pktio_entry(void)
{
odp_pktio_t id;
pktio_entry_t *entry;
@@ -145,7 +129,7 @@ static odp_pktio_t alloc_lock_pktio_entry(odp_pktio_params_t *params)
if (is_free(entry)) {
lock_entry(entry);
if (is_free(entry)) {
- init_pktio_entry(entry, params);
+ init_pktio_entry(entry);
id = i + 1;
return id; /* return with entry locked! */
}
@@ -168,30 +152,14 @@ static int free_pktio_entry(odp_pktio_t id)
return 0;
}
-odp_pktio_t odp_pktio_open(const char *dev, odp_buffer_pool_t pool,
- odp_pktio_params_t *params)
+odp_pktio_t odp_pktio_open(const char *dev, odp_buffer_pool_t pool)
{
odp_pktio_t id;
pktio_entry_t *pktio_entry;
int res;
+ int fanout = 1;
- if (params == NULL) {
- ODP_ERR("Invalid pktio params\n");
- return ODP_PKTIO_INVALID;
- }
-
- switch (params->type) {
- case ODP_PKTIO_TYPE_SOCKET_BASIC:
- case ODP_PKTIO_TYPE_SOCKET_MMSG:
- case ODP_PKTIO_TYPE_SOCKET_MMAP:
- ODP_DBG("Allocating socket pktio\n");
- break;
- default:
- ODP_ERR("Invalid pktio type: %02x\n", params->type);
- return ODP_PKTIO_INVALID;
- }
-
- id = alloc_lock_pktio_entry(params);
+ id = alloc_lock_pktio_entry();
if (id == ODP_PKTIO_INVALID) {
ODP_ERR("No resources available.\n");
return ODP_PKTIO_INVALID;
@@ -200,33 +168,51 @@ odp_pktio_t odp_pktio_open(const char *dev, odp_buffer_pool_t pool,
pktio_entry = get_entry(id);
- switch (params->type) {
- case ODP_PKTIO_TYPE_SOCKET_BASIC:
- case ODP_PKTIO_TYPE_SOCKET_MMSG:
+ ODP_DBG("ODP_PKTIO_USE_FANOUT: %d\n", fanout);
+ if (getenv("ODP_PKTIO_DISABLE_SOCKET_MMAP") == NULL) {
+ pktio_entry->s.params.sock_params.type =
+ ODP_PKTIO_TYPE_SOCKET_MMAP;
+ pktio_entry->s.params.sock_params.fanout = fanout;
+ res = setup_pkt_sock_mmap(&pktio_entry->s.pkt_sock_mmap, dev,
+ pool, fanout);
+ if (res != -1) {
+ ODP_DBG("IO type: ODP_PKTIO_TYPE_SOCKET_MMAP\n");
+ goto done;
+ }
+ close_pkt_sock_mmap(&pktio_entry->s.pkt_sock_mmap);
+ }
+
+ if (getenv("ODP_PKTIO_DISABLE_SOCKET_MMSG") == NULL) {
+ pktio_entry->s.params.sock_params.type =
+ ODP_PKTIO_TYPE_SOCKET_MMSG;
+ pktio_entry->s.params.sock_params.fanout = fanout;
res = setup_pkt_sock(&pktio_entry->s.pkt_sock, dev, pool);
- if (res == -1) {
- close_pkt_sock(&pktio_entry->s.pkt_sock);
- free_pktio_entry(id);
- id = ODP_PKTIO_INVALID;
+ if (res != -1) {
+ ODP_DBG("IO type: ODP_PKTIO_TYPE_SOCKET_MMSG\n");
+ goto done;
}
- break;
- case ODP_PKTIO_TYPE_SOCKET_MMAP:
- res = setup_pkt_sock_mmap(&pktio_entry->s.pkt_sock_mmap, dev,
- pool, params->sock_params.fanout);
- if (res == -1) {
- close_pkt_sock_mmap(&pktio_entry->s.pkt_sock_mmap);
- free_pktio_entry(id);
- id = ODP_PKTIO_INVALID;
+ close_pkt_sock(&pktio_entry->s.pkt_sock);
+ }
+
+ if (getenv("ODP_PKTIO_DISABLE_SOCKET_BASIC") == NULL) {
+ pktio_entry->s.params.sock_params.type =
+ ODP_PKTIO_TYPE_SOCKET_BASIC;
+ pktio_entry->s.params.sock_params.fanout = fanout;
+ res = setup_pkt_sock(&pktio_entry->s.pkt_sock, dev, pool);
+ if (res != -1) {
+ ODP_DBG("IO type: ODP_PKTIO_TYPE_SOCKET_BASIC\n");
+ goto done;
}
- break;
- default:
- free_pktio_entry(id);
- id = ODP_PKTIO_INVALID;
- ODP_ERR("This type of I/O is not supported. Please recompile.\n");
- break;
+ close_pkt_sock(&pktio_entry->s.pkt_sock);
}
unlock_entry(pktio_entry);
+ free_pktio_entry(id);
+ ODP_ERR("Unable to init any I/O type.\n");
+ return ODP_PKTIO_INVALID;
+
+done:
+ unlock_entry(pktio_entry);
return id;
}
Signed-off-by: Ciprian Barbu <ciprian.barbu@linaro.org> --- example/generator/odp_generator.c | 14 ++- example/ipsec/odp_ipsec.c | 38 ++----- example/l2fwd/odp_l2fwd.c | 30 ++---- example/packet/odp_pktio.c | 44 ++------- platform/linux-generic/include/api/odp_packet_io.h | 4 +- .../linux-generic/include/odp_packet_io_internal.h | 6 -- platform/linux-generic/odp_packet_io.c | 110 +++++++++------------ 7 files changed, 78 insertions(+), 168 deletions(-)