[dpdk-dev] [PATCH 1/1] fix the number of operations in libcrypto test
This patch reduce the number of total operations from 1M to 10K, because test is taking too long time now. Fixes: ffbe3be0d4b5 ("app/test: add libcrypto") Signed-off-by: Marcin Kerlin --- app/test/test_cryptodev_perf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/test/test_cryptodev_perf.c b/app/test/test_cryptodev_perf.c index 4aee9af..43a7166 100644 --- a/app/test/test_cryptodev_perf.c +++ b/app/test/test_cryptodev_perf.c @@ -3420,7 +3420,7 @@ test_perf_snow3G_vary_pkt_size(void) static int test_perf_libcrypto_vary_pkt_size(void) { - unsigned int total_operations = 100; + unsigned int total_operations = 1; unsigned int burst_size = { 64 }; unsigned int buf_lengths[] = { 64, 128, 256, 512, 768, 1024, 1280, 1536, 1792, 2048 }; -- 1.9.1
[dpdk-dev] [PATCH v5 2/2] app/testpmd: improve handling of multiprocess
Added lookup for pool name because secondary process should attach to mempool created by primary process rather than create new one. Added function free_shared_dev_data() used at the exit of the testpmd. This causes detach devices data from array rte_eth_dev_data[] shared between all processes. This allows to have a up-to-date list of devices data and run again secondary application with the same name. Signed-off-by: Marcin Kerlin --- app/test-pmd/testpmd.c | 37 +++-- app/test-pmd/testpmd.h | 1 + 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c index e2403c3..78b3a39 100644 --- a/app/test-pmd/testpmd.c +++ b/app/test-pmd/testpmd.c @@ -452,8 +452,11 @@ mbuf_pool_create(uint16_t mbuf_seg_size, unsigned nb_mbuf, rte_mempool_obj_iter(rte_mp, rte_pktmbuf_init, NULL); } else { /* wrapper to rte_mempool_create() */ - rte_mp = rte_pktmbuf_pool_create(pool_name, nb_mbuf, - mb_mempool_cache, 0, mbuf_seg_size, socket_id); + rte_mp = rte_mempool_lookup(pool_name); + if (rte_mp == NULL) + rte_mp = rte_pktmbuf_pool_create(pool_name, + nb_mbuf, mb_mempool_cache, 0, + mbuf_seg_size, socket_id); } } @@ -1611,6 +1614,35 @@ detach_port(uint8_t port_id) return; } +void free_shared_dev_data(portid_t pid) +{ + portid_t pi; + + if (port_id_is_invalid(pid, ENABLED_WARN)) + return; + + /* free data only if the secondary process exits */ + if (rte_eal_process_type() != RTE_PROC_SECONDARY) + return; + + printf("Cleaning device data...\n"); + + FOREACH_PORT(pi, ports) + { + if (pid != pi && pid != (portid_t) RTE_PORT_ALL) + continue; + + if (!port_is_closed(pi)) { + printf("Port %d is not closed now\n", pi); + continue; + } + + if (rte_eth_dev_release_dev_data(pi) < 0) + return; + } + printf("Done\n"); +} + void pmd_test_exit(void) { @@ -1626,6 +1658,7 @@ pmd_test_exit(void) fflush(stdout); stop_port(pt_id); close_port(pt_id); + free_shared_dev_data(pt_id); } } printf("\nBye...\n"); diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h index 2b281cc..3915a06 100644 --- a/app/test-pmd/testpmd.h +++ b/app/test-pmd/testpmd.h @@ -553,6 +553,7 @@ void attach_port(char *identifier); void detach_port(uint8_t port_id); int all_ports_stopped(void); int port_is_started(portid_t port_id); +void free_shared_dev_data(portid_t pid); void pmd_test_exit(void); void fdir_get_infos(portid_t port_id); void fdir_set_flex_mask(portid_t port_id, -- 1.9.1
[dpdk-dev] [PATCH v5 1/2] librte_ether: add protection against overwrite device data
Added protection against overwrite device data in array rte_eth_dev_data[] for the next secondary applications. Secondary process appends in the first free place rather than at the beginning. This behavior prevents overwriting devices data of primary process by secondary process. Signed-off-by: Marcin Kerlin --- lib/librte_ether/rte_ethdev.c | 89 +++--- lib/librte_ether/rte_ethdev.h | 12 + lib/librte_ether/rte_ether_version.map | 6 +++ 3 files changed, 100 insertions(+), 7 deletions(-) diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c index 382c959..89a382c 100644 --- a/lib/librte_ether/rte_ethdev.c +++ b/lib/librte_ether/rte_ethdev.c @@ -176,6 +176,19 @@ rte_eth_dev_allocated(const char *name) return NULL; } +static struct rte_eth_dev_data * +rte_eth_dev_get_dev_data_by_name(const char *name) +{ + unsigned int i; + + for (i = 0; i < RTE_MAX_ETHPORTS; i++) { + if (strcmp(rte_eth_dev_data[i].name, name) == 0) + return &rte_eth_dev_data[i]; + } + + return NULL; +} + static uint8_t rte_eth_dev_find_free_port(void) { @@ -188,10 +201,43 @@ rte_eth_dev_find_free_port(void) return RTE_MAX_ETHPORTS; } +static uint8_t +rte_eth_dev_find_free_dev_data_id(void) +{ + unsigned int i; + + for (i = 0; i < RTE_MAX_ETHPORTS; i++) { + if (!strlen(rte_eth_dev_data[i].name)) + return i; + } + return RTE_MAX_ETHPORTS; +} + +int +rte_eth_dev_release_dev_data(uint8_t port_id) +{ + char device[RTE_ETH_NAME_MAX_LEN]; + struct rte_eth_dev_data *eth_dev_data = NULL; + + /* get device name by port id */ + if (rte_eth_dev_get_name_by_port(port_id, device)) + return -EINVAL; + + /* look for an entry in the device data */ + eth_dev_data = rte_eth_dev_get_dev_data_by_name(device); + if (eth_dev_data == NULL) + return -EINVAL; + + /* clear an entry in the device data */ + memset(eth_dev_data, 0, sizeof(struct rte_eth_dev_data)); + + return 0; +} + struct rte_eth_dev * rte_eth_dev_allocate(const char *name, enum rte_eth_dev_type type) { - uint8_t port_id; + uint8_t port_id, dev_data_id; struct rte_eth_dev *eth_dev; port_id = rte_eth_dev_find_free_port(); @@ -203,17 +249,35 @@ rte_eth_dev_allocate(const char *name, enum rte_eth_dev_type type) if (rte_eth_dev_data == NULL) rte_eth_dev_data_alloc(); + do { + dev_data_id = rte_eth_dev_find_free_dev_data_id(); + } while (!rte_spinlock_trylock(&rte_eth_dev_data[dev_data_id].lock) + && dev_data_id < RTE_MAX_ETHPORTS); + + if (dev_data_id == RTE_MAX_ETHPORTS) { + RTE_PMD_DEBUG_TRACE("Reached maximum number of Ethernet ports " + "by all the processes\n"); + return NULL; + } + if (rte_eth_dev_allocated(name) != NULL) { RTE_PMD_DEBUG_TRACE("Ethernet Device with name %s already allocated!\n", name); return NULL; } + if (rte_eth_dev_get_dev_data_by_name(name) != NULL) { + RTE_PMD_DEBUG_TRACE("Ethernet Device with name %s already " + "allocated by another process!\n", name); + return NULL; + } + eth_dev = &rte_eth_devices[port_id]; - eth_dev->data = &rte_eth_dev_data[port_id]; + eth_dev->data = &rte_eth_dev_data[dev_data_id]; snprintf(eth_dev->data->name, sizeof(eth_dev->data->name), "%s", name); eth_dev->data->port_id = port_id; eth_dev->attached = DEV_ATTACHED; + rte_spinlock_unlock(ð_dev->data->lock); eth_dev->dev_type = type; nb_ports++; return eth_dev; @@ -417,9 +481,7 @@ rte_eth_dev_get_name_by_port(uint8_t port_id, char *name) return -EINVAL; } - /* shouldn't check 'rte_eth_devices[i].data', -* because it might be overwritten by VDEV PMD */ - tmp = rte_eth_dev_data[port_id].name; + tmp = rte_eth_devices[port_id].data->name; strcpy(name, tmp); return 0; } @@ -439,8 +501,7 @@ rte_eth_dev_get_port_by_name(const char *name, uint8_t *port_id) for (i = 0; i < RTE_MAX_ETHPORTS; i++) { if (!strncmp(name, - rte_eth_dev_data[i].name, strlen(name))) { - + rte_eth_devices[i].data->name, strlen(name))) { *port_id = i; return 0; @@ -631,6 +692,8 @@ int rte_eth_dev_detach(uint8_t port_id, char *name) { struct rte_pci_addr addr; + struct rte_eth_dev_dat
[dpdk-dev] [PATCH v5 0/2] app/testpmd: improve multiprocess support
This patch ensure not overwrite device data in the multiprocess application. 1)Changes in the library introduces continuity in array rte_eth_dev_data[] shared between all processes. Secondary process adds new entries in free space instead of overwriting existing entries. 2)Changes in application testpmd allow secondary process to attach the mempool created by primary process rather than create new and in the case of quit or force quit to free devices data from shared array rte_eth_dev_data[]. - How to reproduce the bug: 1) Run primary process: ./testpmd -c 0xf -n 4 --socket-mem='512,0' -w 03:00.1 -w 03:00.0 --proc-type=primary --file-prefix=xz1 -- -i (gdb) print rte_eth_devices[0].data.name $52 = "3:0.1" (gdb) print rte_eth_devices[1].data.name $53 = "3:0.0" 2) Run secondary process: ./testpmd -c 0xf0 --socket-mem='512,0' -n 4 -v -b 03:00.1 -b 03:00.0 --vdev 'eth_pcap0,rx_pcap=/var/log/device1.pcap, tx_pcap=/var/log/device2.pcap' --proc-type=secondary --file-prefix=xz1 -- -i (gdb) print rte_eth_devices[0].data.name $52 = "eth_pcap0" (gdb) print rte_eth_devices[1].data.name $53 = "eth_pcap1" 3) Go back to the primary and re-check: (gdb) print rte_eth_devices[0].data.name $54 = "eth_pcap0" (gdb) print rte_eth_devices[1].data.name $55 = "eth_pcap1" It means that secondary process overwrite data of primary process. This patch fix it and now if we go back to the primary and re-check then everything is fine: (gdb) print rte_eth_devices[0].data.name $56 = "3:0.1" (gdb) print rte_eth_devices[1].data.name $57 = "3:0.0" So after this fix structure rte_eth_dev_data[] will keep all data one after the other instead of overwriting: (gdb) print rte_eth_dev_data[0].name $52 = "3:0.1" (gdb) print rte_eth_dev_data[1].name $53 = "3:0.0" (gdb) print rte_eth_dev_data[2].name $54 = "eth_pcap0" (gdb) print rte_eth_dev_data[3].name $55 = "eth_pcap1" and so on will be append in the next indexes If secondary process will be turned off then also will be deleted from array: (gdb) print rte_eth_dev_data[0].name $52 = "3:0.1" (gdb) print rte_eth_dev_data[1].name $53 = "3:0.0" (gdb) print rte_eth_dev_data[2].name $54 = "" (gdb) print rte_eth_dev_data[3].name $55 = "" this also allows re-use index 2 and 3 for next another process - Breaking ABI: Changes in the library librte_ether causes extending existing structure rte_eth_dev_data with a new field lock. The reason is that this structure is sharing between all the processes so it should be protected against attempting to write from two different processes. Tomasz Kulasek sent announce ABI change in librte_ether on 21 July 2016. I would like to join to this breaking ABI, if it is possible. v2: * fix syntax error in version script v3: * changed scope of function * improved description v4: * fix syntax error in version script v5: * fix header file Marcin Kerlin (2): librte_ether: add protection against overwrite device data app/testpmd: improve handling of multiprocess app/test-pmd/testpmd.c | 37 +- app/test-pmd/testpmd.h | 1 + lib/librte_ether/rte_ethdev.c | 90 +++--- lib/librte_ether/rte_ethdev.h | 12 + lib/librte_ether/rte_ether_version.map | 6 +++ 5 files changed, 136 insertions(+), 10 deletions(-) -- 1.9.1
[dpdk-dev] [PATCH v4 2/2] app/testpmd: improve handling of multiprocess
Added lookup for pool name because secondary process should attach to mempool created by primary process rather than create new one. Added function free_shared_dev_data() used at the exit of the testpmd. This causes detach devices data from array rte_eth_dev_data[] shared between all processes. This allows to have a up-to-date list of devices data and run again secondary application with the same name. Signed-off-by: Marcin Kerlin --- app/test-pmd/testpmd.c | 36 ++-- app/test-pmd/testpmd.h | 1 + 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c index e2403c3..6418cf2 100644 --- a/app/test-pmd/testpmd.c +++ b/app/test-pmd/testpmd.c @@ -452,8 +452,10 @@ mbuf_pool_create(uint16_t mbuf_seg_size, unsigned nb_mbuf, rte_mempool_obj_iter(rte_mp, rte_pktmbuf_init, NULL); } else { /* wrapper to rte_mempool_create() */ - rte_mp = rte_pktmbuf_pool_create(pool_name, nb_mbuf, - mb_mempool_cache, 0, mbuf_seg_size, socket_id); + rte_mp = rte_mempool_lookup(pool_name); + if (rte_mp == NULL) + rte_mp = rte_pktmbuf_pool_create(pool_name, nb_mbuf, + mb_mempool_cache, 0, mbuf_seg_size, socket_id); } } @@ -1611,6 +1613,35 @@ detach_port(uint8_t port_id) return; } +void free_shared_dev_data(portid_t pid) +{ + portid_t pi; + + if (port_id_is_invalid(pid, ENABLED_WARN)) + return; + + /* free data only if the secondary process exits */ + if (rte_eal_process_type() != RTE_PROC_SECONDARY) + return; + + printf("Cleaning device data...\n"); + + FOREACH_PORT(pi, ports) + { + if (pid != pi && pid != (portid_t) RTE_PORT_ALL) + continue; + + if (!port_is_closed(pi)) { + printf("Port %d is not closed now\n", pi); + continue; + } + + if (rte_eth_dev_release_dev_data(pi) < 0) + return; + } + printf("Done\n"); +} + void pmd_test_exit(void) { @@ -1626,6 +1657,7 @@ pmd_test_exit(void) fflush(stdout); stop_port(pt_id); close_port(pt_id); + free_shared_dev_data(pt_id); } } printf("\nBye...\n"); diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h index 2b281cc..3915a06 100644 --- a/app/test-pmd/testpmd.h +++ b/app/test-pmd/testpmd.h @@ -553,6 +553,7 @@ void attach_port(char *identifier); void detach_port(uint8_t port_id); int all_ports_stopped(void); int port_is_started(portid_t port_id); +void free_shared_dev_data(portid_t pid); void pmd_test_exit(void); void fdir_get_infos(portid_t port_id); void fdir_set_flex_mask(portid_t port_id, -- 1.9.1
[dpdk-dev] [PATCH v4 1/2] librte_ether: add protection against overwrite device data
Added prevention not overwrite device data in array rte_eth_dev_data[] for the next secondary applications. Secondary process appends in the first free place rather than at the beginning. This behavior prevents overwriting devices data of primary process by secondary process. Signed-off-by: Marcin Kerlin --- lib/librte_ether/rte_ethdev.c | 90 +++--- lib/librte_ether/rte_ethdev.h | 24 + lib/librte_ether/rte_ether_version.map | 6 +++ 3 files changed, 112 insertions(+), 8 deletions(-) diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c index 382c959..9060df4 100644 --- a/lib/librte_ether/rte_ethdev.c +++ b/lib/librte_ether/rte_ethdev.c @@ -176,6 +176,19 @@ rte_eth_dev_allocated(const char *name) return NULL; } +static struct rte_eth_dev_data * +rte_eth_dev_get_dev_data_by_name(const char *name) +{ + unsigned int i; + + for (i = 0; i < RTE_MAX_ETHPORTS; i++) { + if (strcmp(rte_eth_dev_data[i].name, name) == 0) + return &rte_eth_dev_data[i]; + } + + return NULL; +} + static uint8_t rte_eth_dev_find_free_port(void) { @@ -188,10 +201,43 @@ rte_eth_dev_find_free_port(void) return RTE_MAX_ETHPORTS; } +static uint8_t +rte_eth_dev_find_free_dev_data_id(void) +{ + unsigned int i; + + for (i = 0; i < RTE_MAX_ETHPORTS; i++) { + if (!strlen(rte_eth_dev_data[i].name)) + return i; + } + return RTE_MAX_ETHPORTS; +} + +int +rte_eth_dev_release_dev_data(uint8_t port_id) +{ + char device[RTE_ETH_NAME_MAX_LEN]; + struct rte_eth_dev_data *eth_dev_data = NULL; + + /* get device name by port id */ + if (rte_eth_dev_get_name_by_port(port_id, device)) + return -EINVAL; + + /* look for an entry in the device data */ + eth_dev_data = rte_eth_dev_get_dev_data_by_name(device); + if (eth_dev_data == NULL) + return -EINVAL; + + /* clear an entry in the device data */ + memset(eth_dev_data, 0, sizeof(struct rte_eth_dev_data)); + + return 0; +} + struct rte_eth_dev * rte_eth_dev_allocate(const char *name, enum rte_eth_dev_type type) { - uint8_t port_id; + uint8_t port_id, dev_data_id; struct rte_eth_dev *eth_dev; port_id = rte_eth_dev_find_free_port(); @@ -203,17 +249,35 @@ rte_eth_dev_allocate(const char *name, enum rte_eth_dev_type type) if (rte_eth_dev_data == NULL) rte_eth_dev_data_alloc(); + do { + dev_data_id = rte_eth_dev_find_free_dev_data_id(); + } while (!rte_spinlock_trylock(&rte_eth_dev_data[dev_data_id].lock) + && dev_data_id < RTE_MAX_ETHPORTS); + + if (dev_data_id == RTE_MAX_ETHPORTS) { + RTE_PMD_DEBUG_TRACE("Reached maximum number of Ethernet ports by all " + "the processes\n"); + return NULL; + } + if (rte_eth_dev_allocated(name) != NULL) { RTE_PMD_DEBUG_TRACE("Ethernet Device with name %s already allocated!\n", name); return NULL; } + if (rte_eth_dev_get_dev_data_by_name(name) != NULL) { + RTE_PMD_DEBUG_TRACE("Ethernet Device with name %s already allocated by " + "another process!\n", name); + return NULL; + } + eth_dev = &rte_eth_devices[port_id]; - eth_dev->data = &rte_eth_dev_data[port_id]; + eth_dev->data = &rte_eth_dev_data[dev_data_id]; snprintf(eth_dev->data->name, sizeof(eth_dev->data->name), "%s", name); eth_dev->data->port_id = port_id; eth_dev->attached = DEV_ATTACHED; + rte_spinlock_unlock(ð_dev->data->lock); eth_dev->dev_type = type; nb_ports++; return eth_dev; @@ -417,9 +481,7 @@ rte_eth_dev_get_name_by_port(uint8_t port_id, char *name) return -EINVAL; } - /* shouldn't check 'rte_eth_devices[i].data', -* because it might be overwritten by VDEV PMD */ - tmp = rte_eth_dev_data[port_id].name; + tmp = rte_eth_devices[port_id].data->name; strcpy(name, tmp); return 0; } @@ -438,9 +500,7 @@ rte_eth_dev_get_port_by_name(const char *name, uint8_t *port_id) for (i = 0; i < RTE_MAX_ETHPORTS; i++) { - if (!strncmp(name, - rte_eth_dev_data[i].name, strlen(name))) { - + if (!strncmp(name, rte_eth_devices[i].data->name, strlen(name))) { *port_id = i; return 0; @@ -631,6 +691,8 @@ int rte_eth_dev_detach(uint8_t port_id, char *name) { struct rte_pci_addr addr; +
[dpdk-dev] [PATCH v4 0/2] app/testpmd: improve multiprocess support
This patch ensure not overwrite device data in the multiprocess application. 1)Changes in the library introduces continuity in array rte_eth_dev_data[] shared between all processes. Secondary process adds new entries in free space instead of overwriting existing entries. 2)Changes in application testpmd allow secondary process to attach the mempool created by primary process rather than create new and in the case of quit or force quit to free devices data from shared array rte_eth_dev_data[]. - How to reproduce the bug: 1) Run primary process: -c 0xf -n 4 --socket-mem='512,0' -w 03:00.1 -w 03:00.0 --proc-type=primary --file-prefix=xz1 -- -i (gdb) print rte_eth_devices[0].data.name $52 = "3:0.1" (gdb) print rte_eth_devices[1].data.name $53 = "3:0.0" 2) Run secondary process: -c 0xf0 --socket-mem='512,0' -n 4 -v -b 03:00.1 -b 03:00.0 -b 01:00.0 -b 01:00.0 --vdev 'eth_pcap0,rx_pcap=/var/log/device1.pcap,tx_pcap=/var/log/device2.pcap' --proc-type=secondary --file-prefix=xz1 -- -i (gdb) print rte_eth_devices[0].data.name $52 = "eth_pcap0" (gdb) print rte_eth_devices[1].data.name $53 = "eth_pcap1" 3) Go back to the primary and re-check: (gdb) print rte_eth_devices[0].data.name $54 = "eth_pcap0" (gdb) print rte_eth_devices[1].data.name $55 = "eth_pcap1" It means that secondary process overwrite data of primary process. This patch fix it and now if we go back to the primary and re-check then everything is fine: (gdb) print rte_eth_devices[0].data.name $56 = "3:0.1" (gdb) print rte_eth_devices[1].data.name $57 = "3:0.0" So after this fix structure rte_eth_dev_data[] will keep all data one after the other instead of overwriting: (gdb) print rte_eth_dev_data[0].name $52 = "3:0.1" (gdb) print rte_eth_dev_data[1].name $53 = "3:0.0" (gdb) print rte_eth_dev_data[2].name $54 = "eth_pcap0" (gdb) print rte_eth_dev_data[3].name $55 = "eth_pcap1" and so on will be append in the next indexes If secondary process will be turned off then also will be deleted from array: (gdb) print rte_eth_dev_data[0].name $52 = "3:0.1" (gdb) print rte_eth_dev_data[1].name $53 = "3:0.0" (gdb) print rte_eth_dev_data[2].name $54 = "" (gdb) print rte_eth_dev_data[3].name $55 = "" this also allows re-use index 2 and 3 for next another process - Breaking ABI: Changes in the library librte_ether causes extending existing structure rte_eth_dev_data with a new field lock. The reason is that this structure is sharing between all the processes so it should be protected against attempting to write from two different processes. Tomasz Kulasek sent announce ABI change in librte_ether on 21 July 2016. I would like to join to this breaking ABI, if it is possible. v2: * fix syntax error in version script v3: * changed scope of function * improved description v4: * fix syntax error in version script Marcin Kerlin (2): librte_ether: add protection against overwrite device data app/testpmd: improve handling of multiprocess app/test-pmd/testpmd.c | 36 +- app/test-pmd/testpmd.h | 1 + lib/librte_ether/rte_ethdev.c | 90 +++--- lib/librte_ether/rte_ethdev.h | 24 + lib/librte_ether/rte_ether_version.map | 6 +++ 5 files changed, 147 insertions(+), 10 deletions(-) -- 1.9.1
[dpdk-dev] [PATCH v4 0/2] app/testpmd: improve multiprocess support
This patch ensure not overwrite device data in the multiprocess application. 1)Changes in the library introduces continuity in array rte_eth_dev_data[] shared between all processes. Secondary process adds new entries in free space instead of overwriting existing entries. 2)Changes in application testpmd allow secondary process to attach the mempool created by primary process rather than create new and in the case of quit or force quit to free devices data from shared array rte_eth_dev_data[]. - How to reproduce the bug: 1) Run primary process: -c 0xf -n 4 --socket-mem='512,0' -w 03:00.1 -w 03:00.0 --proc-type=primary --file-prefix=xz1 -- -i (gdb) print rte_eth_devices[0].data.name $52 = "3:0.1" (gdb) print rte_eth_devices[1].data.name $53 = "3:0.0" 2) Run secondary process: -c 0xf0 --socket-mem='512,0' -n 4 -v -b 03:00.1 -b 03:00.0 -b 01:00.0 -b 01:00.0 --vdev 'eth_pcap0,rx_pcap=/var/log/device1.pcap,tx_pcap=/var/log/device2.pcap' --proc-type=secondary --file-prefix=xz1 -- -i (gdb) print rte_eth_devices[0].data.name $52 = "eth_pcap0" (gdb) print rte_eth_devices[1].data.name $53 = "eth_pcap1" 3) Go back to the primary and re-check: (gdb) print rte_eth_devices[0].data.name $54 = "eth_pcap0" (gdb) print rte_eth_devices[1].data.name $55 = "eth_pcap1" It means that secondary process overwrite data of primary process. This patch fix it and now if we go back to the primary and re-check then everything is fine: (gdb) print rte_eth_devices[0].data.name $56 = "3:0.1" (gdb) print rte_eth_devices[1].data.name $57 = "3:0.0" So after this fix structure rte_eth_dev_data[] will keep all data one after the other instead of overwriting: (gdb) print rte_eth_dev_data[0].name $52 = "3:0.1" (gdb) print rte_eth_dev_data[1].name $53 = "3:0.0" (gdb) print rte_eth_dev_data[2].name $54 = "eth_pcap0" (gdb) print rte_eth_dev_data[3].name $55 = "eth_pcap1" and so on will be append in the next indexes If secondary process will be turned off then also will be deleted from array: (gdb) print rte_eth_dev_data[0].name $52 = "3:0.1" (gdb) print rte_eth_dev_data[1].name $53 = "3:0.0" (gdb) print rte_eth_dev_data[2].name $54 = "" (gdb) print rte_eth_dev_data[3].name $55 = "" this also allows re-use index 2 and 3 for next another process - Breaking ABI: Changes in the library librte_ether causes extending existing structure rte_eth_dev_data with a new field lock. The reason is that this structure is sharing between all the processes so it should be protected against attempting to write from two different processes. Tomasz Kulasek sent announce ABI change in librte_ether on 21 July 2016. I would like to join to this breaking ABI, if it is possible. v2: * fix syntax error in version script v3: * changed scope of function * improved description v4: * fix syntax error in version script Marcin Kerlin (2): librte_ether: add protection against overwrite device data app/testpmd: improve handling of multiprocess app/test-pmd/testpmd.c | 36 +- app/test-pmd/testpmd.h | 1 + lib/librte_ether/rte_ethdev.c | 90 +++--- lib/librte_ether/rte_ethdev.h | 24 + lib/librte_ether/rte_ether_version.map | 6 +++ 5 files changed, 147 insertions(+), 10 deletions(-) -- 1.9.1
[dpdk-dev] [PATCH v3 2/2] app/testpmd: improve handling of multiprocess
Added lookup for pool name because secondary process should attach to mempool created by primary process rather than create new one. Added function free_shared_dev_data() used at the exit of the testpmd. This causes detach devices data from array rte_eth_dev_data[] shared between all processes. This allows to have a up-to-date list of devices data and run again secondary application with the same name. Signed-off-by: Marcin Kerlin --- app/test-pmd/testpmd.c | 36 ++-- app/test-pmd/testpmd.h | 1 + 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c index 1428974..b02f4eb 100644 --- a/app/test-pmd/testpmd.c +++ b/app/test-pmd/testpmd.c @@ -453,8 +453,10 @@ mbuf_pool_create(uint16_t mbuf_seg_size, unsigned nb_mbuf, rte_mempool_obj_iter(rte_mp, rte_pktmbuf_init, NULL); } else { /* wrapper to rte_mempool_create() */ - rte_mp = rte_pktmbuf_pool_create(pool_name, nb_mbuf, - mb_mempool_cache, 0, mbuf_seg_size, socket_id); + rte_mp = rte_mempool_lookup(pool_name); + if (rte_mp == NULL) + rte_mp = rte_pktmbuf_pool_create(pool_name, nb_mbuf, + mb_mempool_cache, 0, mbuf_seg_size, socket_id); } } @@ -1610,6 +1612,35 @@ detach_port(uint8_t port_id) return; } +void free_shared_dev_data(portid_t pid) +{ + portid_t pi; + + if (port_id_is_invalid(pid, ENABLED_WARN)) + return; + + /* free data only if the secondary process exits */ + if (rte_eal_process_type() != RTE_PROC_SECONDARY) + return; + + printf("Cleaning device data...\n"); + + FOREACH_PORT(pi, ports) + { + if (pid != pi && pid != (portid_t) RTE_PORT_ALL) + continue; + + if (!port_is_closed(pi)) { + printf("Port %d is not closed now\n", pi); + continue; + } + + if (rte_eth_dev_release_dev_data(pi) < 0) + return; + } + printf("Done\n"); +} + void pmd_test_exit(void) { @@ -1625,6 +1656,7 @@ pmd_test_exit(void) fflush(stdout); stop_port(pt_id); close_port(pt_id); + free_shared_dev_data(pt_id); } } printf("\nBye...\n"); diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h index 2b281cc..3915a06 100644 --- a/app/test-pmd/testpmd.h +++ b/app/test-pmd/testpmd.h @@ -553,6 +553,7 @@ void attach_port(char *identifier); void detach_port(uint8_t port_id); int all_ports_stopped(void); int port_is_started(portid_t port_id); +void free_shared_dev_data(portid_t pid); void pmd_test_exit(void); void fdir_get_infos(portid_t port_id); void fdir_set_flex_mask(portid_t port_id, -- 1.9.1
[dpdk-dev] [PATCH v3 1/2] librte_ether: ensure not overwrite device data in mp app
Added prevention not overwrite device data in array rte_eth_dev_data[]. Secondary process appends in the first free place rather than at the beginning. This behavior prevents overwriting devices data of primary process by secondary process. Signed-off-by: Marcin Kerlin --- lib/librte_ether/rte_ethdev.c | 90 +++--- lib/librte_ether/rte_ethdev.h | 24 + lib/librte_ether/rte_ether_version.map | 7 +++ 3 files changed, 113 insertions(+), 8 deletions(-) diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c index f62a9ec..faaa170 100644 --- a/lib/librte_ether/rte_ethdev.c +++ b/lib/librte_ether/rte_ethdev.c @@ -177,6 +177,19 @@ rte_eth_dev_allocated(const char *name) return NULL; } +static struct rte_eth_dev_data * +rte_eth_dev_get_dev_data_by_name(const char *name) +{ + unsigned int i; + + for (i = 0; i < RTE_MAX_ETHPORTS; i++) { + if (strcmp(rte_eth_dev_data[i].name, name) == 0) + return &rte_eth_dev_data[i]; + } + + return NULL; +} + static uint8_t rte_eth_dev_find_free_port(void) { @@ -189,10 +202,43 @@ rte_eth_dev_find_free_port(void) return RTE_MAX_ETHPORTS; } +static uint8_t +rte_eth_dev_find_free_dev_data_id(void) +{ + unsigned int i; + + for (i = 0; i < RTE_MAX_ETHPORTS; i++) { + if (!strlen(rte_eth_dev_data[i].name)) + return i; + } + return RTE_MAX_ETHPORTS; +} + +int +rte_eth_dev_release_dev_data(uint8_t port_id) +{ + char device[RTE_ETH_NAME_MAX_LEN]; + struct rte_eth_dev_data *eth_dev_data = NULL; + + /* get device name by port id */ + if (rte_eth_dev_get_name_by_port(port_id, device)) + return -EINVAL; + + /* look for an entry in the device data */ + eth_dev_data = rte_eth_dev_get_dev_data_by_name(device); + if (eth_dev_data == NULL) + return -EINVAL; + + /* clear an entry in the device data */ + memset(eth_dev_data, 0, sizeof(struct rte_eth_dev_data)); + + return 0; +} + struct rte_eth_dev * rte_eth_dev_allocate(const char *name, enum rte_eth_dev_type type) { - uint8_t port_id; + uint8_t port_id, dev_data_id; struct rte_eth_dev *eth_dev; port_id = rte_eth_dev_find_free_port(); @@ -204,17 +250,35 @@ rte_eth_dev_allocate(const char *name, enum rte_eth_dev_type type) if (rte_eth_dev_data == NULL) rte_eth_dev_data_alloc(); + do { + dev_data_id = rte_eth_dev_find_free_dev_data_id(); + } while (!rte_spinlock_trylock(&rte_eth_dev_data[dev_data_id].lock) + && dev_data_id < RTE_MAX_ETHPORTS); + + if (dev_data_id == RTE_MAX_ETHPORTS) { + RTE_PMD_DEBUG_TRACE("Reached maximum number of Ethernet ports by all " + "the processes\n"); + return NULL; + } + if (rte_eth_dev_allocated(name) != NULL) { RTE_PMD_DEBUG_TRACE("Ethernet Device with name %s already allocated!\n", name); return NULL; } + if (rte_eth_dev_get_dev_data_by_name(name) != NULL) { + RTE_PMD_DEBUG_TRACE("Ethernet Device with name %s already allocated by " + "another process!\n", name); + return NULL; + } + eth_dev = &rte_eth_devices[port_id]; - eth_dev->data = &rte_eth_dev_data[port_id]; + eth_dev->data = &rte_eth_dev_data[dev_data_id]; snprintf(eth_dev->data->name, sizeof(eth_dev->data->name), "%s", name); eth_dev->data->port_id = port_id; eth_dev->attached = DEV_ATTACHED; + rte_spinlock_unlock(ð_dev->data->lock); eth_dev->dev_type = type; nb_ports++; return eth_dev; @@ -418,9 +482,7 @@ rte_eth_dev_get_name_by_port(uint8_t port_id, char *name) return -EINVAL; } - /* shouldn't check 'rte_eth_devices[i].data', -* because it might be overwritten by VDEV PMD */ - tmp = rte_eth_dev_data[port_id].name; + tmp = rte_eth_devices[port_id].data->name; strcpy(name, tmp); return 0; } @@ -439,9 +501,7 @@ rte_eth_dev_get_port_by_name(const char *name, uint8_t *port_id) for (i = 0; i < RTE_MAX_ETHPORTS; i++) { - if (!strncmp(name, - rte_eth_dev_data[i].name, strlen(name))) { - + if (!strncmp(name, rte_eth_devices[i].data->name, strlen(name))) { *port_id = i; return 0; @@ -632,6 +692,8 @@ int rte_eth_dev_detach(uint8_t port_id, char *name) { struct rte_pci_addr addr; + struct rte_eth_dev_data *eth_dev_data = NULL
[dpdk-dev] [PATCH v3 0/2] app/testpmd: improve multiprocess support
This patch ensure not overwrite device data in the multiprocess application. 1)Changes in the library introduces continuity in array rte_eth_dev_data[] shared between all processes. Secondary process adds new entries in free space instead of overwriting existing entries. 2)Changes in application testpmd allow secondary process to attach the mempool created by primary process rather than create new and in the case of quit or force quit to free devices data from shared array rte_eth_dev_data[]. - How to reproduce the bug: 1) Run primary process: -c 0xf -n 4 --socket-mem='512,0' -w 03:00.1 -w 03:00.0 --proc-type=primary --file-prefix=xz1 -- -i (gdb) print rte_eth_devices[0].data.name $52 = "3:0.1" (gdb) print rte_eth_devices[1].data.name $53 = "3:0.0" 2) Run secondary process: -c 0xf0 --socket-mem='512,0' -n 4 -v -b 03:00.1 -b 03:00.0 -b 01:00.0 -b 01:00.0 --vdev 'eth_pcap0,rx_pcap=/var/log/device1.pcap,tx_pcap=/var/log/device2.pcap' --proc-type=secondary --file-prefix=xz1 -- -i (gdb) print rte_eth_devices[0].data.name $52 = "eth_pcap0" (gdb) print rte_eth_devices[1].data.name $53 = "eth_pcap1" 3) Go back to the primary and re-check: (gdb) print rte_eth_devices[0].data.name $54 = "eth_pcap0" (gdb) print rte_eth_devices[1].data.name $55 = "eth_pcap1" It means that secondary process overwrite data of primary process. This patch fix it and now if we go back to the primary and re-check then everything is fine: (gdb) print rte_eth_devices[0].data.name $56 = "3:0.1" (gdb) print rte_eth_devices[1].data.name $57 = "3:0.0" So after this fix structure rte_eth_dev_data[] will keep all data one after the other instead of overwriting: (gdb) print rte_eth_dev_data[0].name $52 = "3:0.1" (gdb) print rte_eth_dev_data[1].name $53 = "3:0.0" (gdb) print rte_eth_dev_data[2].name $54 = "eth_pcap0" (gdb) print rte_eth_dev_data[3].name $55 = "eth_pcap1" and so on will be append in the next indexes If secondary process will be turned off then also will be deleted from array: (gdb) print rte_eth_dev_data[0].name $52 = "3:0.1" (gdb) print rte_eth_dev_data[1].name $53 = "3:0.0" (gdb) print rte_eth_dev_data[2].name $54 = "" (gdb) print rte_eth_dev_data[3].name $55 = "" this also allows re-use index 2 and 3 for next another process - Breaking ABI: Changes in the library librte_ether causes extending existing structure rte_eth_dev_data with a new field lock. The reason is that this structure is sharing between all the processes so it should be protected against attempting to write from two different processes. Tomasz Kulasek sent announce ABI change in librte_ether on 21 July 2016. I would like to join to this breaking ABI, if it is possible. v2: * fix syntax error in version script v3: * changed scope of function * improved description Marcin Kerlin (2): librte_ether: ensure not overwrite device data in mp app app/testpmd: improve handling of multiprocess app/test-pmd/testpmd.c | 36 +- app/test-pmd/testpmd.h | 1 + lib/librte_ether/rte_ethdev.c | 90 +++--- lib/librte_ether/rte_ethdev.h | 24 + lib/librte_ether/rte_ether_version.map | 7 +++ 5 files changed, 148 insertions(+), 10 deletions(-) -- 1.9.1
[dpdk-dev] [PATCH v2 2/2] app/testpmd: improve handling of multiprocess
Added lookup for pool name because secondary process should attach to mempool created by primary process rather than create new one. Added function free_shared_dev_data() used at the exit of the testpmd. This causes detach devices data from array rte_eth_dev_data[] shared between all processes. This allows to have a up-to-date list of devices data and run again secondary application with the same name. Signed-off-by: Marcin Kerlin --- app/test-pmd/testpmd.c | 36 ++-- app/test-pmd/testpmd.h | 1 + 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c index 30749a4..51f6aee 100644 --- a/app/test-pmd/testpmd.c +++ b/app/test-pmd/testpmd.c @@ -452,8 +452,10 @@ mbuf_pool_create(uint16_t mbuf_seg_size, unsigned nb_mbuf, rte_mempool_obj_iter(rte_mp, rte_pktmbuf_init, NULL); } else { /* wrapper to rte_mempool_create() */ - rte_mp = rte_pktmbuf_pool_create(pool_name, nb_mbuf, - mb_mempool_cache, 0, mbuf_seg_size, socket_id); + rte_mp = rte_mempool_lookup(pool_name); + if (rte_mp == NULL) + rte_mp = rte_pktmbuf_pool_create(pool_name, nb_mbuf, + mb_mempool_cache, 0, mbuf_seg_size, socket_id); } } @@ -1609,6 +1611,35 @@ detach_port(uint8_t port_id) return; } +void free_shared_dev_data(portid_t pid) +{ + portid_t pi; + + if (port_id_is_invalid(pid, ENABLED_WARN)) + return; + + /* free data only if the secondary process exits */ + if (rte_eal_process_type() != RTE_PROC_SECONDARY) + return; + + printf("Cleaning device data...\n"); + + FOREACH_PORT(pi, ports) + { + if (pid != pi && pid != (portid_t) RTE_PORT_ALL) + continue; + + if (!port_is_closed(pi)) { + printf("Port %d is not closed now\n", pi); + continue; + } + + if (rte_eth_dev_release_dev_data(pi) < 0) + return; + } + printf("Done\n"); +} + void pmd_test_exit(void) { @@ -1624,6 +1655,7 @@ pmd_test_exit(void) fflush(stdout); stop_port(pt_id); close_port(pt_id); + free_shared_dev_data(pt_id); } } printf("\nBye...\n"); diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h index 2b281cc..3915a06 100644 --- a/app/test-pmd/testpmd.h +++ b/app/test-pmd/testpmd.h @@ -553,6 +553,7 @@ void attach_port(char *identifier); void detach_port(uint8_t port_id); int all_ports_stopped(void); int port_is_started(portid_t port_id); +void free_shared_dev_data(portid_t pid); void pmd_test_exit(void); void fdir_get_infos(portid_t port_id); void fdir_set_flex_mask(portid_t port_id, -- 1.9.1
[dpdk-dev] [PATCH v2 1/2] librte_ether: ensure not overwrite device data in mp app
Added prevention not overwrite device data in array rte_eth_dev_data[]. Secondary process appends in the first free place rather than at the beginning. This behavior prevents overwriting devices of primary process by secondary process. Signed-off-by: Marcin Kerlin --- lib/librte_ether/rte_ethdev.c | 90 +++--- lib/librte_ether/rte_ethdev.h | 24 + lib/librte_ether/rte_ether_version.map | 7 +++ 3 files changed, 113 insertions(+), 8 deletions(-) diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c index 382c959..dadd77a 100644 --- a/lib/librte_ether/rte_ethdev.c +++ b/lib/librte_ether/rte_ethdev.c @@ -176,6 +176,19 @@ rte_eth_dev_allocated(const char *name) return NULL; } +struct rte_eth_dev_data * +rte_eth_dev_data_allocated(const char *name) +{ + unsigned int i; + + for (i = 0; i < RTE_MAX_ETHPORTS; i++) { + if (strcmp(rte_eth_dev_data[i].name, name) == 0) + return &rte_eth_dev_data[i]; + } + + return NULL; +} + static uint8_t rte_eth_dev_find_free_port(void) { @@ -188,10 +201,43 @@ rte_eth_dev_find_free_port(void) return RTE_MAX_ETHPORTS; } +static uint8_t +rte_eth_dev_find_free_dev_data_id(void) +{ + unsigned int i; + + for (i = 0; i < RTE_MAX_ETHPORTS; i++) { + if (!strlen(rte_eth_dev_data[i].name)) + return i; + } + return RTE_MAX_ETHPORTS; +} + +int +rte_eth_dev_release_dev_data(uint8_t port_id) +{ + char device[RTE_ETH_NAME_MAX_LEN]; + struct rte_eth_dev_data *eth_dev_data = NULL; + + /* get device name by port id */ + if (rte_eth_dev_get_name_by_port(port_id, device)) + return -EINVAL; + + /* look for an entry in the device data */ + eth_dev_data = rte_eth_dev_data_allocated(device); + if (eth_dev_data == NULL) + return -EINVAL; + + /* clear an entry in the device data */ + memset(eth_dev_data, 0, sizeof(struct rte_eth_dev_data)); + + return 0; +} + struct rte_eth_dev * rte_eth_dev_allocate(const char *name, enum rte_eth_dev_type type) { - uint8_t port_id; + uint8_t port_id, dev_data_id; struct rte_eth_dev *eth_dev; port_id = rte_eth_dev_find_free_port(); @@ -203,17 +249,35 @@ rte_eth_dev_allocate(const char *name, enum rte_eth_dev_type type) if (rte_eth_dev_data == NULL) rte_eth_dev_data_alloc(); + do { + dev_data_id = rte_eth_dev_find_free_dev_data_id(); + } while (!rte_spinlock_trylock(&rte_eth_dev_data[dev_data_id].lock) + && dev_data_id < RTE_MAX_ETHPORTS); + + if (dev_data_id == RTE_MAX_ETHPORTS) { + RTE_PMD_DEBUG_TRACE("Reached maximum number of Ethernet ports by all " + "the processes\n"); + return NULL; + } + if (rte_eth_dev_allocated(name) != NULL) { RTE_PMD_DEBUG_TRACE("Ethernet Device with name %s already allocated!\n", name); return NULL; } + if (rte_eth_dev_data_allocated(name) != NULL) { + RTE_PMD_DEBUG_TRACE("Ethernet Device with name %s already allocated by " + "another process!\n", name); + return NULL; + } + eth_dev = &rte_eth_devices[port_id]; - eth_dev->data = &rte_eth_dev_data[port_id]; + eth_dev->data = &rte_eth_dev_data[dev_data_id]; snprintf(eth_dev->data->name, sizeof(eth_dev->data->name), "%s", name); eth_dev->data->port_id = port_id; eth_dev->attached = DEV_ATTACHED; + rte_spinlock_unlock(ð_dev->data->lock); eth_dev->dev_type = type; nb_ports++; return eth_dev; @@ -417,9 +481,7 @@ rte_eth_dev_get_name_by_port(uint8_t port_id, char *name) return -EINVAL; } - /* shouldn't check 'rte_eth_devices[i].data', -* because it might be overwritten by VDEV PMD */ - tmp = rte_eth_dev_data[port_id].name; + tmp = rte_eth_devices[port_id].data->name; strcpy(name, tmp); return 0; } @@ -438,9 +500,7 @@ rte_eth_dev_get_port_by_name(const char *name, uint8_t *port_id) for (i = 0; i < RTE_MAX_ETHPORTS; i++) { - if (!strncmp(name, - rte_eth_dev_data[i].name, strlen(name))) { - + if (!strncmp(name, rte_eth_devices[i].data->name, strlen(name))) { *port_id = i; return 0; @@ -631,6 +691,8 @@ int rte_eth_dev_detach(uint8_t port_id, char *name) { struct rte_pci_addr addr; + struct rte_eth_dev_data *eth_dev_data = NULL; + char dev
[dpdk-dev] [PATCH v2 0/2] app/testpmd: improve multiprocess support
This patch ensure not overwrite device data in the multiprocess application. 1)Changes in the library introduces continuity in array rte_eth_dev_data[] shared between all processes. Secondary process adds new entries in free space instead of overwriting existing entries. 2)Changes in application testpmd allow secondary process to attach the mempool created by primary process rather than create new and in the case of quit or force quit to free devices data from shared array rte_eth_dev_data[]. Breaking ABI: Changes in the library librte_ether causes extending existing structure rte_eth_dev_data with a new field lock. The reason is that this structure is sharing between all the processes so it should be protected against attempting to write from two different processes. Tomasz Kulasek sent announce ABI change in librte_ether on 21 July 2016. I would like to join to this breaking ABI, if it is possible. v2: * fix syntax error in version script Marcin Kerlin (2): librte_ether: ensure not overwrite device data in mp app app/testpmd: improve handling of multiprocess app/test-pmd/testpmd.c | 36 +- app/test-pmd/testpmd.h | 1 + lib/librte_ether/rte_ethdev.c | 90 +++--- lib/librte_ether/rte_ethdev.h | 24 + lib/librte_ether/rte_ether_version.map | 7 +++ 5 files changed, 148 insertions(+), 10 deletions(-) -- 1.9.1
[dpdk-dev] [PATCH v2 0/2] app/testpmd: improve multiprocess support
This patch ensure not overwrite device data in the multiprocess application. 1)Changes in the library introduces continuity in array rte_eth_dev_data[] shared between all processes. Secondary process adds new entries in free space instead of overwriting existing entries. 2)Changes in application testpmd allow secondary process to attach the mempool created by primary process rather than create new and in the case of quit or force quit to free devices data from shared array rte_eth_dev_data[]. Breaking ABI: Changes in the library librte_ether causes extending existing structure rte_eth_dev_data with a new field lock. The reason is that this structure is sharing between all the processes so it should be protected against attempting to write from two different processes. Tomasz Kulasek sent announce ABI change in librte_ether on 21 July 2016. I would like to join to this breaking ABI, if it is possible. v2: * fix syntax error in version script Marcin Kerlin (2): librte_ether: ensure not overwrite device data in mp app app/testpmd: improve handling of multiprocess app/test-pmd/testpmd.c | 36 +- app/test-pmd/testpmd.h | 1 + lib/librte_ether/rte_ethdev.c | 90 +++--- lib/librte_ether/rte_ethdev.h | 24 + lib/librte_ether/rte_ether_version.map | 7 +++ 5 files changed, 148 insertions(+), 10 deletions(-) -- 1.9.1
[dpdk-dev] [PATCH 2/2] app/testpmd: improve handling of multiprocess
Added lookup for pool name because secondary process should attach to mempool created by primary process rather than create new one. Added function free_shared_dev_data() used at the exit of the testpmd. This causes detach devices data from array rte_eth_dev_data[] shared between all processes. This allows to have a up-to-date list of devices data and run again secondary application with the same name. Signed-off-by: Marcin Kerlin --- app/test-pmd/testpmd.c | 36 ++-- app/test-pmd/testpmd.h | 1 + 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c index 1428974..b02f4eb 100644 --- a/app/test-pmd/testpmd.c +++ b/app/test-pmd/testpmd.c @@ -453,8 +453,10 @@ mbuf_pool_create(uint16_t mbuf_seg_size, unsigned nb_mbuf, rte_mempool_obj_iter(rte_mp, rte_pktmbuf_init, NULL); } else { /* wrapper to rte_mempool_create() */ - rte_mp = rte_pktmbuf_pool_create(pool_name, nb_mbuf, - mb_mempool_cache, 0, mbuf_seg_size, socket_id); + rte_mp = rte_mempool_lookup(pool_name); + if (rte_mp == NULL) + rte_mp = rte_pktmbuf_pool_create(pool_name, nb_mbuf, + mb_mempool_cache, 0, mbuf_seg_size, socket_id); } } @@ -1610,6 +1612,35 @@ detach_port(uint8_t port_id) return; } +void free_shared_dev_data(portid_t pid) +{ + portid_t pi; + + if (port_id_is_invalid(pid, ENABLED_WARN)) + return; + + /* free data only if the secondary process exits */ + if (rte_eal_process_type() != RTE_PROC_SECONDARY) + return; + + printf("Cleaning device data...\n"); + + FOREACH_PORT(pi, ports) + { + if (pid != pi && pid != (portid_t) RTE_PORT_ALL) + continue; + + if (!port_is_closed(pi)) { + printf("Port %d is not closed now\n", pi); + continue; + } + + if (rte_eth_dev_release_dev_data(pi) < 0) + return; + } + printf("Done\n"); +} + void pmd_test_exit(void) { @@ -1625,6 +1656,7 @@ pmd_test_exit(void) fflush(stdout); stop_port(pt_id); close_port(pt_id); + free_shared_dev_data(pt_id); } } printf("\nBye...\n"); diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h index 2b281cc..3915a06 100644 --- a/app/test-pmd/testpmd.h +++ b/app/test-pmd/testpmd.h @@ -553,6 +553,7 @@ void attach_port(char *identifier); void detach_port(uint8_t port_id); int all_ports_stopped(void); int port_is_started(portid_t port_id); +void free_shared_dev_data(portid_t pid); void pmd_test_exit(void); void fdir_get_infos(portid_t port_id); void fdir_set_flex_mask(portid_t port_id, -- 1.9.1
[dpdk-dev] [PATCH 1/2] librte_ether: ensure not overwrite device data in mp app
Added prevention not overwrite device data in array rte_eth_dev_data[]. Secondary process appends in the first free place rather than at the beginning. This behavior prevents overwriting devices of primary process by secondary process. Signed-off-by: Marcin Kerlin --- lib/librte_ether/rte_ethdev.c | 90 +++--- lib/librte_ether/rte_ethdev.h | 24 + lib/librte_ether/rte_ether_version.map | 7 +++ 3 files changed, 113 insertions(+), 8 deletions(-) diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c index f62a9ec..78e42bf 100644 --- a/lib/librte_ether/rte_ethdev.c +++ b/lib/librte_ether/rte_ethdev.c @@ -177,6 +177,19 @@ rte_eth_dev_allocated(const char *name) return NULL; } +struct rte_eth_dev_data * +rte_eth_dev_data_allocated(const char *name) +{ + unsigned int i; + + for (i = 0; i < RTE_MAX_ETHPORTS; i++) { + if (strcmp(rte_eth_dev_data[i].name, name) == 0) + return &rte_eth_dev_data[i]; + } + + return NULL; +} + static uint8_t rte_eth_dev_find_free_port(void) { @@ -189,10 +202,43 @@ rte_eth_dev_find_free_port(void) return RTE_MAX_ETHPORTS; } +static uint8_t +rte_eth_dev_find_free_dev_data_id(void) +{ + unsigned int i; + + for (i = 0; i < RTE_MAX_ETHPORTS; i++) { + if (!strlen(rte_eth_dev_data[i].name)) + return i; + } + return RTE_MAX_ETHPORTS; +} + +int +rte_eth_dev_release_dev_data(uint8_t port_id) +{ + char device[RTE_ETH_NAME_MAX_LEN]; + struct rte_eth_dev_data *eth_dev_data = NULL; + + /* get device name by port id */ + if (rte_eth_dev_get_name_by_port(port_id, device)) + return -EINVAL; + + /* look for an entry in the device data */ + eth_dev_data = rte_eth_dev_data_allocated(device); + if (eth_dev_data == NULL) + return -EINVAL; + + /* clear an entry in the device data */ + memset(eth_dev_data, 0, sizeof(struct rte_eth_dev_data)); + + return 0; +} + struct rte_eth_dev * rte_eth_dev_allocate(const char *name, enum rte_eth_dev_type type) { - uint8_t port_id; + uint8_t port_id, dev_data_id; struct rte_eth_dev *eth_dev; port_id = rte_eth_dev_find_free_port(); @@ -204,17 +250,35 @@ rte_eth_dev_allocate(const char *name, enum rte_eth_dev_type type) if (rte_eth_dev_data == NULL) rte_eth_dev_data_alloc(); + do { + dev_data_id = rte_eth_dev_find_free_dev_data_id(); + } while (!rte_spinlock_trylock(&rte_eth_dev_data[dev_data_id].lock) + && dev_data_id < RTE_MAX_ETHPORTS); + + if (dev_data_id == RTE_MAX_ETHPORTS) { + RTE_PMD_DEBUG_TRACE("Reached maximum number of Ethernet ports by all " + "the processes\n"); + return NULL; + } + if (rte_eth_dev_allocated(name) != NULL) { RTE_PMD_DEBUG_TRACE("Ethernet Device with name %s already allocated!\n", name); return NULL; } + if (rte_eth_dev_data_allocated(name) != NULL) { + RTE_PMD_DEBUG_TRACE("Ethernet Device with name %s already allocated by " + "another process!\n", name); + return NULL; + } + eth_dev = &rte_eth_devices[port_id]; - eth_dev->data = &rte_eth_dev_data[port_id]; + eth_dev->data = &rte_eth_dev_data[dev_data_id]; snprintf(eth_dev->data->name, sizeof(eth_dev->data->name), "%s", name); eth_dev->data->port_id = port_id; eth_dev->attached = DEV_ATTACHED; + rte_spinlock_unlock(ð_dev->data->lock); eth_dev->dev_type = type; nb_ports++; return eth_dev; @@ -418,9 +482,7 @@ rte_eth_dev_get_name_by_port(uint8_t port_id, char *name) return -EINVAL; } - /* shouldn't check 'rte_eth_devices[i].data', -* because it might be overwritten by VDEV PMD */ - tmp = rte_eth_dev_data[port_id].name; + tmp = rte_eth_devices[port_id].data->name; strcpy(name, tmp); return 0; } @@ -439,9 +501,7 @@ rte_eth_dev_get_port_by_name(const char *name, uint8_t *port_id) for (i = 0; i < RTE_MAX_ETHPORTS; i++) { - if (!strncmp(name, - rte_eth_dev_data[i].name, strlen(name))) { - + if (!strncmp(name, rte_eth_devices[i].data->name, strlen(name))) { *port_id = i; return 0; @@ -632,6 +692,8 @@ int rte_eth_dev_detach(uint8_t port_id, char *name) { struct rte_pci_addr addr; + struct rte_eth_dev_data *eth_dev_data = NULL; + char dev
[dpdk-dev] [PATCH 0/2] app/testpmd: improve multiprocess support
This patch ensure not overwrite device data in the multiprocess application. 1)Changes in the library introduces continuity in array rte_eth_dev_data[] shared between all processes. Secondary process adds new entries in free space instead of overwriting existing entries. 2)Changes in application testpmd allow secondary process to attach the mempool created by primary process rather than create new and in the case of quit or force quit to free devices data from shared array rte_eth_dev_data[]. Breaking ABI: Changes in the library librte_ether causes extending existing structure rte_eth_dev_data with a new field lock. The reason is that this structure is sharing between all the processes so it should be protected against attempting to write from two different processes. Tomasz Kulasek sent announce ABI change in librte_ether on 21 July 2016. I would like to join to this breaking ABI, if it is possible. Marcin Kerlin (2): librte_ether: ensure not overwrite device data in mp app app/testpmd: improve handling of multiprocess app/test-pmd/testpmd.c | 36 +- app/test-pmd/testpmd.h | 1 + lib/librte_ether/rte_ethdev.c | 90 +++--- lib/librte_ether/rte_ethdev.h | 24 + lib/librte_ether/rte_ether_version.map | 7 +++ 5 files changed, 148 insertions(+), 10 deletions(-) -- 1.9.1
[dpdk-dev] [PATCH 2/2] app/testpmd: fix handling of multiprocess
Added lookup for pool name because secondary process should attach to mempool created by primary process rather than create new. Added function free_mp_shared_dev_data() which causes that if secondary process quit or force quit then detach own devices from common array rte_eth_dev_data[] for all processes. This allows to have a up-to-date list of devices and run again secondary application with the same name. Signed-off-by: Marcin Kerlin --- app/test-pmd/testpmd.c | 30 -- app/test-pmd/testpmd.h | 1 + 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c index 1428974..2fa33d0 100644 --- a/app/test-pmd/testpmd.c +++ b/app/test-pmd/testpmd.c @@ -453,8 +453,10 @@ mbuf_pool_create(uint16_t mbuf_seg_size, unsigned nb_mbuf, rte_mempool_obj_iter(rte_mp, rte_pktmbuf_init, NULL); } else { /* wrapper to rte_mempool_create() */ - rte_mp = rte_pktmbuf_pool_create(pool_name, nb_mbuf, - mb_mempool_cache, 0, mbuf_seg_size, socket_id); + rte_mp = rte_mempool_lookup(pool_name); + if (rte_mp == NULL) + rte_mp = rte_pktmbuf_pool_create(pool_name, nb_mbuf, + mb_mempool_cache, 0, mbuf_seg_size, socket_id); } } @@ -1610,6 +1612,29 @@ detach_port(uint8_t port_id) return; } +void free_mp_shared_dev_data(portid_t pid) +{ + portid_t pi; + + if (port_id_is_invalid(pid, ENABLED_WARN)) + return; + + /* free data only if the secondary process exits */ + if (rte_eal_process_type() != RTE_PROC_SECONDARY) + return; + + FOREACH_PORT(pi, ports) { + if (pid != pi && pid != (portid_t)RTE_PORT_ALL) + continue; + + if (!port_is_closed(pi)) + return; + + if (rte_eth_dev_release_dev_data(pi) < 0) + return; + } +} + void pmd_test_exit(void) { @@ -1625,6 +1650,7 @@ pmd_test_exit(void) fflush(stdout); stop_port(pt_id); close_port(pt_id); + free_mp_shared_dev_data(pt_id); } } printf("\nBye...\n"); diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h index 2b281cc..63f82f7 100644 --- a/app/test-pmd/testpmd.h +++ b/app/test-pmd/testpmd.h @@ -553,6 +553,7 @@ void attach_port(char *identifier); void detach_port(uint8_t port_id); int all_ports_stopped(void); int port_is_started(portid_t port_id); +void free_mp_shared_dev_data(portid_t pid); void pmd_test_exit(void); void fdir_get_infos(portid_t port_id); void fdir_set_flex_mask(portid_t port_id, -- 1.9.1
[dpdk-dev] [PATCH 1/2] lib/librte_ether: ensure not overwrite device data
Added ensure consistent device data in the multiprocess application. Primary process creates array rte_eth_dev_data[] and secondary process appends in the first free place rather than at the beginning. This behavior prevents overwriting devices of primary process by secondary process. Two arrays rte_eth_dev_data[] and rte_eth_devices[] are shifted relative to each other and it required the addition new functions to search separately data. Signed-off-by: Marcin Kerlin --- lib/librte_ether/rte_ethdev.c | 87 ++ lib/librte_ether/rte_ethdev.h | 23 + lib/librte_ether/rte_ether_version.map | 8 3 files changed, 110 insertions(+), 8 deletions(-) diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c index f62a9ec..a8f89c9 100644 --- a/lib/librte_ether/rte_ethdev.c +++ b/lib/librte_ether/rte_ethdev.c @@ -177,6 +177,19 @@ rte_eth_dev_allocated(const char *name) return NULL; } +struct rte_eth_dev_data * +rte_eth_dev_data_shared_allocated(const char *name) +{ + unsigned i; + + for (i = 0; i < RTE_MAX_ETHPORTS; i++) { + if (strcmp(rte_eth_dev_data[i].name, name) == 0) + return &rte_eth_dev_data[i]; + } + + return NULL; +} + static uint8_t rte_eth_dev_find_free_port(void) { @@ -189,10 +202,43 @@ rte_eth_dev_find_free_port(void) return RTE_MAX_ETHPORTS; } +static uint8_t +rte_eth_dev_find_free_dev_data_id(void) +{ + unsigned i; + + for (i = 0; i < RTE_MAX_ETHPORTS; i++) { + if (!strlen(rte_eth_dev_data[i].name)) + return i; + } + return RTE_MAX_ETHPORTS; +} + +int +rte_eth_dev_release_dev_data(uint8_t port_id) +{ + char device[RTE_ETH_NAME_MAX_LEN]; + struct rte_eth_dev_data *eth_dev_data = NULL; + + /* get device name by port id */ + if (rte_eth_dev_get_name_by_port(port_id, device)) + return -EINVAL; + + /* look for an entry in the shared device data */ + eth_dev_data = rte_eth_dev_data_shared_allocated(device); + if (eth_dev_data == NULL) + return -EINVAL; + + /* clear an entry in the shared device data */ + memset(eth_dev_data, 0, sizeof(struct rte_eth_dev_data)); + + return 0; +} + struct rte_eth_dev * rte_eth_dev_allocate(const char *name, enum rte_eth_dev_type type) { - uint8_t port_id; + uint8_t port_id, dev_data_id; struct rte_eth_dev *eth_dev; port_id = rte_eth_dev_find_free_port(); @@ -204,14 +250,28 @@ rte_eth_dev_allocate(const char *name, enum rte_eth_dev_type type) if (rte_eth_dev_data == NULL) rte_eth_dev_data_alloc(); + dev_data_id = rte_eth_dev_find_free_dev_data_id(); + + if (dev_data_id == RTE_MAX_ETHPORTS) { + RTE_PMD_DEBUG_TRACE("Reached maximum number of Ethernet ports by all " + "the processes\n"); + return NULL; + } + if (rte_eth_dev_allocated(name) != NULL) { RTE_PMD_DEBUG_TRACE("Ethernet Device with name %s already allocated!\n", name); return NULL; } + if (rte_eth_dev_data_shared_allocated(name) != NULL) { + RTE_PMD_DEBUG_TRACE("Ethernet Device with name %s already allocated by " + "another process!\n", name); + return NULL; + } + eth_dev = &rte_eth_devices[port_id]; - eth_dev->data = &rte_eth_dev_data[port_id]; + eth_dev->data = &rte_eth_dev_data[dev_data_id]; snprintf(eth_dev->data->name, sizeof(eth_dev->data->name), "%s", name); eth_dev->data->port_id = port_id; eth_dev->attached = DEV_ATTACHED; @@ -237,6 +297,7 @@ rte_eth_dev_create_unique_device_name(char *name, size_t size, int rte_eth_dev_release_port(struct rte_eth_dev *eth_dev) { + if (eth_dev == NULL) return -EINVAL; @@ -418,9 +479,7 @@ rte_eth_dev_get_name_by_port(uint8_t port_id, char *name) return -EINVAL; } - /* shouldn't check 'rte_eth_devices[i].data', -* because it might be overwritten by VDEV PMD */ - tmp = rte_eth_dev_data[port_id].name; + tmp = rte_eth_devices[port_id].data->name; strcpy(name, tmp); return 0; } @@ -439,9 +498,7 @@ rte_eth_dev_get_port_by_name(const char *name, uint8_t *port_id) for (i = 0; i < RTE_MAX_ETHPORTS; i++) { - if (!strncmp(name, - rte_eth_dev_data[i].name, strlen(name))) { - + if (!strncmp(name, rte_eth_devices[i].data->name, strlen(name))) { *port_id = i; return 0; @@ -632,6 +689,8 @@ int rte_eth_dev_detach(uint8_
[dpdk-dev] [PATCH 0/2] add ensure consistent device data in multiprocess mode
This patch ensure not overwrite device data in the multiprocess application. 1)Changes in the library introduces continuity in device data rte_eth_dev_data[] common for to all processes. Functionality detach cleans data of detachable device and leaves space for other devices or for the next run app. 2)Changes in application testpmd allow secondary process to attach the mempool created by primary process rather than create new and in the case of quit or force quit to free devices of this process from shared array rte_eth_dev_data[]. Marcin Kerlin (2): lib/librte_ether: ensure not overwrite device data in multiprocess app app/testpmd: fix handling of multiprocess app/test-pmd/testpmd.c | 30 +++- app/test-pmd/testpmd.h | 1 + lib/librte_ether/rte_ethdev.c | 87 ++ lib/librte_ether/rte_ethdev.h | 23 + lib/librte_ether/rte_ether_version.map | 8 5 files changed, 139 insertions(+), 10 deletions(-) -- 1.9.1
[dpdk-dev] [PATCH v5 1/1] eal: fix resource leak of mapped memory
Patch fixes resource leak in rte_eal_hugepage_attach() where mapped files were not freed back to the OS in case of failure. Patch uses the behavior of Linux munmap: "It is not an error if the indicated range does not contain any mapped pages". Coverity issue: 13295, 13296, 13303 Fixes: af75078fece3 ("first public release") Signed-off-by: Marcin Kerlin Acked-by: Sergio Gonzalez Monroy --- v5: -shift the history of changes v4: -removed keyword const from pointer and dependent on that casting (void *) v3: -removed redundant casting -removed update error message v2: -unmapping also previous addresses lib/librte_eal/linuxapp/eal/eal_memory.c | 13 ++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/lib/librte_eal/linuxapp/eal/eal_memory.c b/lib/librte_eal/linuxapp/eal/eal_memory.c index 79d1d2d..c935765 100644 --- a/lib/librte_eal/linuxapp/eal/eal_memory.c +++ b/lib/librte_eal/linuxapp/eal/eal_memory.c @@ -1399,7 +1399,7 @@ int rte_eal_hugepage_attach(void) { const struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config; - const struct hugepage_file *hp = NULL; + struct hugepage_file *hp = NULL; unsigned num_hp = 0; unsigned i, s = 0; /* s used to track the segment number */ off_t size; @@ -1481,7 +1481,7 @@ rte_eal_hugepage_attach(void) size = getFileSize(fd_hugepage); hp = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd_hugepage, 0); - if (hp == NULL) { + if (hp == MAP_FAILED) { RTE_LOG(ERR, EAL, "Could not mmap %s\n", eal_hugepage_info_path()); goto error; } @@ -1545,12 +1545,19 @@ rte_eal_hugepage_attach(void) s++; } /* unmap the hugepage config file, since we are done using it */ - munmap((void *)(uintptr_t)hp, size); + munmap(hp, size); close(fd_zero); close(fd_hugepage); return 0; error: + s = 0; + while (s < RTE_MAX_MEMSEG && mcfg->memseg[s].len > 0) { + munmap(mcfg->memseg[s].addr, mcfg->memseg[s].len); + s++; + } + if (hp != NULL && hp != MAP_FAILED) + munmap(hp, size); if (fd_zero >= 0) close(fd_zero); if (fd_hugepage >= 0) -- 1.9.1
[dpdk-dev] [PATCH v4 1/1] eal: fix resource leak of mapped memory
Patch fixes resource leak in rte_eal_hugepage_attach() where mapped files were not freed back to the OS in case of failure. Patch uses the behavior of Linux munmap: "It is not an error if the indicated range does not contain any mapped pages". v4: 1)removed keyword const from pointer and dependent on that casting (void *) v3: 1)removed redundant casting 2)removed update error message v2: 1)unmapping also previous addresses Coverity issue: 13295, 13296, 13303 Fixes: af75078fece3 ("first public release") Signed-off-by: Marcin Kerlin --- lib/librte_eal/linuxapp/eal/eal_memory.c | 13 ++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/lib/librte_eal/linuxapp/eal/eal_memory.c b/lib/librte_eal/linuxapp/eal/eal_memory.c index 79d1d2d..c935765 100644 --- a/lib/librte_eal/linuxapp/eal/eal_memory.c +++ b/lib/librte_eal/linuxapp/eal/eal_memory.c @@ -1399,7 +1399,7 @@ int rte_eal_hugepage_attach(void) { const struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config; - const struct hugepage_file *hp = NULL; + struct hugepage_file *hp = NULL; unsigned num_hp = 0; unsigned i, s = 0; /* s used to track the segment number */ off_t size; @@ -1481,7 +1481,7 @@ rte_eal_hugepage_attach(void) size = getFileSize(fd_hugepage); hp = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd_hugepage, 0); - if (hp == NULL) { + if (hp == MAP_FAILED) { RTE_LOG(ERR, EAL, "Could not mmap %s\n", eal_hugepage_info_path()); goto error; } @@ -1545,12 +1545,19 @@ rte_eal_hugepage_attach(void) s++; } /* unmap the hugepage config file, since we are done using it */ - munmap((void *)(uintptr_t)hp, size); + munmap(hp, size); close(fd_zero); close(fd_hugepage); return 0; error: + s = 0; + while (s < RTE_MAX_MEMSEG && mcfg->memseg[s].len > 0) { + munmap(mcfg->memseg[s].addr, mcfg->memseg[s].len); + s++; + } + if (hp != NULL && hp != MAP_FAILED) + munmap(hp, size); if (fd_zero >= 0) close(fd_zero); if (fd_hugepage >= 0) -- 1.9.1
[dpdk-dev] [PATCH 1/1] eal: fix typo in error message
Minor typo fix to error message Fixes: 148f963fb532 ("xen: core library changes") Signed-off-by: Marcin Kerlin --- lib/librte_eal/linuxapp/eal/eal_memory.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/librte_eal/linuxapp/eal/eal_memory.c b/lib/librte_eal/linuxapp/eal/eal_memory.c index 79d1d2d..2d6eef6 100644 --- a/lib/librte_eal/linuxapp/eal/eal_memory.c +++ b/lib/librte_eal/linuxapp/eal/eal_memory.c @@ -1417,7 +1417,7 @@ rte_eal_hugepage_attach(void) if (internal_config.xen_dom0_support) { #ifdef RTE_LIBRTE_XEN_DOM0 if (rte_xen_dom0_memory_attach() < 0) { - RTE_LOG(ERR, EAL,"Failed to attach memory setments of primay " + RTE_LOG(ERR, EAL, "Failed to attach memory segments of primary " "process\n"); return -1; } -- 1.9.1
[dpdk-dev] [PATCH v3 1/1] eal: fix resource leak of mapped memory
Patch fixes resource leak in rte_eal_hugepage_attach() where mapped files were not freed back to the OS in case of failure. Patch uses the behavior of Linux munmap: "It is not an error if the indicated range does not contain any mapped pages". V3: 1)removed redundant casting 2)removed update error message V2: 1)unmapping also previous addresses Coverity issue: 13295, 13296, 13303 Fixes: af75078fece3 ("first public release") Signed-off-by: Marcin Kerlin --- lib/librte_eal/linuxapp/eal/eal_memory.c | 11 +-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/librte_eal/linuxapp/eal/eal_memory.c b/lib/librte_eal/linuxapp/eal/eal_memory.c index 79d1d2d..44ff8e1 100644 --- a/lib/librte_eal/linuxapp/eal/eal_memory.c +++ b/lib/librte_eal/linuxapp/eal/eal_memory.c @@ -1481,7 +1481,7 @@ rte_eal_hugepage_attach(void) size = getFileSize(fd_hugepage); hp = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd_hugepage, 0); - if (hp == NULL) { + if (hp == MAP_FAILED) { RTE_LOG(ERR, EAL, "Could not mmap %s\n", eal_hugepage_info_path()); goto error; } @@ -1545,12 +1545,19 @@ rte_eal_hugepage_attach(void) s++; } /* unmap the hugepage config file, since we are done using it */ - munmap((void *)(uintptr_t)hp, size); + munmap((void *)hp, size); close(fd_zero); close(fd_hugepage); return 0; error: + s = 0; + while (s < RTE_MAX_MEMSEG && mcfg->memseg[s].len > 0) { + munmap(mcfg->memseg[s].addr, mcfg->memseg[s].len); + s++; + } + if (hp != NULL && hp != MAP_FAILED) + munmap((void *)hp, size); if (fd_zero >= 0) close(fd_zero); if (fd_hugepage >= 0) -- 1.9.1
[dpdk-dev] [PATCH 1/1] vhost: fix null pointer dereference
Return value of function get_device() is not checking before dereference. Fix this problem by adding checking condition. Coverity issue: 119262 Fixes: 77d20126b4c2 ("vhost-user: handle message to enable vring") Signed-off-by: Marcin Kerlin --- lib/librte_vhost/vhost_user/virtio-net-user.c | 6 +- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/librte_vhost/vhost_user/virtio-net-user.c b/lib/librte_vhost/vhost_user/virtio-net-user.c index f5248bc..94959f2 100644 --- a/lib/librte_vhost/vhost_user/virtio-net-user.c +++ b/lib/librte_vhost/vhost_user/virtio-net-user.c @@ -332,9 +332,13 @@ int user_set_vring_enable(struct vhost_device_ctx ctx, struct vhost_vring_state *state) { - struct virtio_net *dev = get_device(ctx); + struct virtio_net *dev; int enable = (int)state->num; + dev = get_device(ctx); + if (dev == NULL) + return -1; + RTE_LOG(INFO, VHOST_CONFIG, "set queue enable: %d to qp idx: %d\n", enable, state->index); -- 1.9.1
[dpdk-dev] [PATCH v2 1/1] eal: fix resource leak of mapped memory
Patch fixes resource leak in rte_eal_hugepage_attach() where mapped files were not freed back to the OS in case of failure. Patch uses the behavior of Linux munmap: "It is not an error if the indicated range does not contain any mapped pages". Coverity issue: 13295, 13296, 13303 Fixes: af75078fece3 ("first public release") Signed-off-by: Marcin Kerlin --- lib/librte_eal/linuxapp/eal/eal_memory.c | 11 +-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/librte_eal/linuxapp/eal/eal_memory.c b/lib/librte_eal/linuxapp/eal/eal_memory.c index 79d1d2d..1834fa0 100644 --- a/lib/librte_eal/linuxapp/eal/eal_memory.c +++ b/lib/librte_eal/linuxapp/eal/eal_memory.c @@ -1417,7 +1417,7 @@ rte_eal_hugepage_attach(void) if (internal_config.xen_dom0_support) { #ifdef RTE_LIBRTE_XEN_DOM0 if (rte_xen_dom0_memory_attach() < 0) { - RTE_LOG(ERR, EAL,"Failed to attach memory setments of primay " + RTE_LOG(ERR, EAL, "Failed to attach memory segments of primary " "process\n"); return -1; } @@ -1481,7 +1481,7 @@ rte_eal_hugepage_attach(void) size = getFileSize(fd_hugepage); hp = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd_hugepage, 0); - if (hp == NULL) { + if (hp == MAP_FAILED) { RTE_LOG(ERR, EAL, "Could not mmap %s\n", eal_hugepage_info_path()); goto error; } @@ -1551,6 +1551,13 @@ rte_eal_hugepage_attach(void) return 0; error: + s = 0; + while (s < RTE_MAX_MEMSEG && mcfg->memseg[s].len > 0) { + munmap(mcfg->memseg[s].addr, mcfg->memseg[s].len); + s++; + } + if (hp != NULL && hp != MAP_FAILED) + munmap((void *)(uintptr_t)hp, size); if (fd_zero >= 0) close(fd_zero); if (fd_hugepage >= 0) -- 1.9.1
[dpdk-dev] [PATCH 1/1] ip_pipeline: fix null pointer dereference
Return value of function app_pipeline_type_find is not checking before dereference. Fix this problem by adding checking condition. Coverity issue: 127196 Fixes: b4aee0fb9c6d ("examples/ip_pipeline: reconfigure thread binding dynamically") Signed-off-by: Marcin Kerlin --- examples/ip_pipeline/thread_fe.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/examples/ip_pipeline/thread_fe.c b/examples/ip_pipeline/thread_fe.c index d1b72b4..6c547ca 100644 --- a/examples/ip_pipeline/thread_fe.c +++ b/examples/ip_pipeline/thread_fe.c @@ -81,6 +81,9 @@ app_pipeline_enable(struct app_params *app, p_params = &app->pipeline_params[pipeline_id]; p_type = app_pipeline_type_find(app, p_params->type); + if (p_type == NULL) + return -1; + if (p->enabled == 1) return -1; -- 1.9.1
[dpdk-dev] [PATCH 1/1] lib/librte_cmdline: fix added checking return value
Unchecked return value: value returned from a function rdline_init is not checked, fix added checking return value and in the case of failure frees memory and return null pointer. Fixes: af75078fece3 ("first public release") Coverity ID 13204 Signed-off-by: Marcin Kerlin --- lib/librte_cmdline/cmdline.c | 10 -- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/librte_cmdline/cmdline.c b/lib/librte_cmdline/cmdline.c index c405878..a9c47be 100644 --- a/lib/librte_cmdline/cmdline.c +++ b/lib/librte_cmdline/cmdline.c @@ -130,6 +130,7 @@ struct cmdline * cmdline_new(cmdline_parse_ctx_t *ctx, const char *prompt, int s_in, int s_out) { struct cmdline *cl; + int ret; if (!ctx || !prompt) return NULL; @@ -142,8 +143,13 @@ cmdline_new(cmdline_parse_ctx_t *ctx, const char *prompt, int s_in, int s_out) cl->s_out = s_out; cl->ctx = ctx; - rdline_init(&cl->rdl, cmdline_write_char, - cmdline_valid_buffer, cmdline_complete_buffer); + ret = rdline_init(&cl->rdl, cmdline_write_char, cmdline_valid_buffer, + cmdline_complete_buffer); + if (ret != 0) { + free(cl); + return NULL; + } + cl->rdl.opaque = cl; cmdline_set_prompt(cl, prompt); rdline_newline(&cl->rdl, cl->prompt); -- 1.9.1
[dpdk-dev] [PATCH 1/1] lib/librte_eal: fix resource leak
Fix issue reported by Coverity. Coverity ID 13295, 13296, 13303: Resource leak: The system resource will not be reclaimed and reused, reducing the future availability of the resource. In rte_eal_hugepage_attach: Leak of memory or pointers to system resources. Fixes: af75078fece3 ("first public release") Signed-off-by: Marcin Kerlin --- lib/librte_eal/linuxapp/eal/eal_memory.c | 12 +++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/lib/librte_eal/linuxapp/eal/eal_memory.c b/lib/librte_eal/linuxapp/eal/eal_memory.c index 5b9132c..6320aa0 100644 --- a/lib/librte_eal/linuxapp/eal/eal_memory.c +++ b/lib/librte_eal/linuxapp/eal/eal_memory.c @@ -1475,13 +1475,17 @@ rte_eal_hugepage_attach(void) "and retry running both primary " "and secondary processes\n"); } + + if (base_addr != MAP_FAILED) + munmap((void *)(uintptr_t)base_addr, mcfg->memseg[s].len); + goto error; } } size = getFileSize(fd_hugepage); hp = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd_hugepage, 0); - if (hp == NULL) { + if (hp == MAP_FAILED) { RTE_LOG(ERR, EAL, "Could not mmap %s\n", eal_hugepage_info_path()); goto error; } @@ -1535,6 +1539,10 @@ rte_eal_hugepage_attach(void) addr != RTE_PTR_ADD(base_addr, offset)) { RTE_LOG(ERR, EAL, "Could not mmap %s\n", hp[i].filepath); + + if (addr != MAP_FAILED) + munmap((void *)(uintptr_t)addr, mapping_size); + goto error; } offset+=mapping_size; @@ -1551,6 +1559,8 @@ rte_eal_hugepage_attach(void) return 0; error: + if (hp != NULL && hp != MAP_FAILED) + munmap((void *) (uintptr_t) hp, size); if (fd_zero >= 0) close(fd_zero); if (fd_hugepage >= 0) -- 1.9.1
[dpdk-dev] [PATCH 1/1] examples/distributor: fix unchecked return value
Fix issue reported by Coverity. Coverity ID 13207: Value returned from a function is not checked for errors before being used. Fixes: 07db4a975094 ("examples/distributor: new sample app") Signed-off-by: Marcin Kerlin --- examples/distributor/main.c | 17 + 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/examples/distributor/main.c b/examples/distributor/main.c index c0201a9..8238520 100644 --- a/examples/distributor/main.c +++ b/examples/distributor/main.c @@ -178,19 +178,25 @@ struct lcore_params { struct rte_mempool *mem_pool; }; -static void +static int quit_workers(struct rte_distributor *d, struct rte_mempool *p) { const unsigned num_workers = rte_lcore_count() - 2; unsigned i; struct rte_mbuf *bufs[num_workers]; - rte_mempool_get_bulk(p, (void *)bufs, num_workers); + + if (rte_mempool_get_bulk(p, (void *)bufs, num_workers) != 0) { + printf("line %d: Error getting mbufs from pool\n", __LINE__); + return -1; + } for (i = 0; i < num_workers; i++) bufs[i]->hash.rss = i << 1; rte_distributor_process(d, bufs, num_workers); rte_mempool_put_bulk(p, (void *)bufs, num_workers); + + return 0; } static int @@ -258,7 +264,8 @@ lcore_rx(struct lcore_params *p) * get packets till quit_signal is actually been * received and they gracefully shutdown */ - quit_workers(d, mem_pool); + if (quit_workers(d, mem_pool) != 0) + return -1; /* rx thread should quit at last */ return 0; } @@ -588,7 +595,9 @@ main(int argc, char *argv[]) } /* call lcore_main on master core only */ struct lcore_params p = { 0, d, output_ring, mbuf_pool}; - lcore_rx(&p); + + if (lcore_rx(&p) != 0) + return -1; RTE_LCORE_FOREACH_SLAVE(lcore_id) { if (rte_eal_wait_lcore(lcore_id) < 0) -- 1.9.1
[dpdk-dev] [PATCH] examples/ip_pipeline: fix out-of-bounds write
CID 124567: In the function app_init_eal(struct app params * app) number of entries into array exceeds the size of the array if the conditions are fulfilled. Fixes: 7f64b9c004aa ("examples/ip_pipeline: rework config file syntax") Signed-off-by: Marcin Kerlin --- examples/ip_pipeline/app.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/ip_pipeline/app.h b/examples/ip_pipeline/app.h index 55a9841..e775024 100644 --- a/examples/ip_pipeline/app.h +++ b/examples/ip_pipeline/app.h @@ -415,7 +415,7 @@ struct app_eal_params { #endif #ifndef APP_EAL_ARGC -#define APP_EAL_ARGC 32 +#define APP_EAL_ARGC 64 #endif #ifndef APP_MAX_PIPELINE_TYPES -- 1.9.1
[dpdk-dev] [PATCH v2 1/1] examples/ip_pipeline: fix wrong size of argument
v2: added fixline CID 120150: Wrong size of the allocated memory. Passing argument as size of pointer (8UL) instead of size of structure app_pipeline_firewall_rule. Fixes: 67ebdbef0c31 ("examples/ip_pipeline: add bulk update of firewall rules") Signed-off-by: Marcin Kerlin --- examples/ip_pipeline/pipeline/pipeline_firewall.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/ip_pipeline/pipeline/pipeline_firewall.c b/examples/ip_pipeline/pipeline/pipeline_firewall.c index 320b25d..fd897d5 100644 --- a/examples/ip_pipeline/pipeline/pipeline_firewall.c +++ b/examples/ip_pipeline/pipeline/pipeline_firewall.c @@ -834,7 +834,7 @@ app_pipeline_firewall_add_bulk(struct app_params *app, rules[i] = app_pipeline_firewall_rule_find(p, &keys[i]); new_rules[i] = (rules[i] == NULL); if (rules[i] == NULL) { - rules[i] = rte_malloc(NULL, sizeof(rules[i]), + rules[i] = rte_malloc(NULL, sizeof(*rules[i]), RTE_CACHE_LINE_SIZE); if (rules[i] == NULL) { -- 1.9.1
[dpdk-dev] [examples/ip_pipeline: fix wrong size of argument 1/1]
CID 120150: Wrong size of the allocated memory. Passing argument as size of pointer (8UL) instead of size of structure app_pipeline_firewall_rule. Signed-off-by: Marcin Kerlin --- examples/ip_pipeline/pipeline/pipeline_firewall.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/ip_pipeline/pipeline/pipeline_firewall.c b/examples/ip_pipeline/pipeline/pipeline_firewall.c index 320b25d..fd897d5 100644 --- a/examples/ip_pipeline/pipeline/pipeline_firewall.c +++ b/examples/ip_pipeline/pipeline/pipeline_firewall.c @@ -834,7 +834,7 @@ app_pipeline_firewall_add_bulk(struct app_params *app, rules[i] = app_pipeline_firewall_rule_find(p, &keys[i]); new_rules[i] = (rules[i] == NULL); if (rules[i] == NULL) { - rules[i] = rte_malloc(NULL, sizeof(rules[i]), + rules[i] = rte_malloc(NULL, sizeof(*rules[i]), RTE_CACHE_LINE_SIZE); if (rules[i] == NULL) { -- 1.9.1
[dpdk-dev] [PATCH v3 1/1] jobstats: added function abort for job
This patch adds new function rte_jobstats_abort. It marks *job* as finished and time of this work will be add to management time instead of execution time. This function should be used instead of rte_jobstats_finish if condition occurs, condition is defined by the application for example when receiving n>0 packets. Example of usage is added to the example l2fwd-jobstats. At maximum load do-while loop inside Idle job will be execute once because one or more jobs waiting to be executed, so this time should not be include as the execution time by calling rte_jobstats_abort(). v2: * removed redundant field v3: * added an example of using Signed-off-by: Marcin Kerlin --- examples/l2fwd-jobstats/main.c | 9 - lib/librte_jobstats/rte_jobstats.c | 20 lib/librte_jobstats/rte_jobstats.h | 14 ++ lib/librte_jobstats/rte_jobstats_version.map | 7 +++ 4 files changed, 49 insertions(+), 1 deletion(-) diff --git a/examples/l2fwd-jobstats/main.c b/examples/l2fwd-jobstats/main.c index 7b59f4e..bd64e74 100644 --- a/examples/l2fwd-jobstats/main.c +++ b/examples/l2fwd-jobstats/main.c @@ -577,10 +577,13 @@ l2fwd_main_loop(void) */ rte_jobstats_start(&qconf->jobs_context, &qconf->idle_job); + uint64_t repeats = 0; + do { uint8_t i; uint64_t now = rte_get_timer_cycles(); + repeats++; need_manage = qconf->flush_timer.expire < now; /* Check if we was esked to give a stats. */ stats_read_pending = @@ -591,7 +594,11 @@ l2fwd_main_loop(void) need_manage = qconf->rx_timers[i].expire < now; } while (!need_manage); - rte_jobstats_finish(&qconf->idle_job, qconf->idle_job.target); + + if (likely(repeats != 1)) + rte_jobstats_finish(&qconf->idle_job, qconf->idle_job.target); + else + rte_jobstats_abort(&qconf->idle_job); rte_timer_manage(); rte_jobstats_context_finish(&qconf->jobs_context); diff --git a/lib/librte_jobstats/rte_jobstats.c b/lib/librte_jobstats/rte_jobstats.c index 2eaac0c..2b42050 100644 --- a/lib/librte_jobstats/rte_jobstats.c +++ b/lib/librte_jobstats/rte_jobstats.c @@ -170,6 +170,26 @@ rte_jobstats_start(struct rte_jobstats_context *ctx, struct rte_jobstats *job) } int +rte_jobstats_abort(struct rte_jobstats *job) +{ + struct rte_jobstats_context *ctx; + uint64_t now, exec_time; + + /* Some sanity check. */ + if (unlikely(job == NULL || job->context == NULL)) + return -EINVAL; + + ctx = job->context; + now = get_time(); + exec_time = now - ctx->state_time; + ADD_TIME_MIN_MAX(ctx, management, exec_time); + ctx->state_time = now; + job->context = NULL; + + return 0; +} + +int rte_jobstats_finish(struct rte_jobstats *job, int64_t job_value) { struct rte_jobstats_context *ctx; diff --git a/lib/librte_jobstats/rte_jobstats.h b/lib/librte_jobstats/rte_jobstats.h index de6a89a..c2b285f 100644 --- a/lib/librte_jobstats/rte_jobstats.h +++ b/lib/librte_jobstats/rte_jobstats.h @@ -237,6 +237,20 @@ int rte_jobstats_start(struct rte_jobstats_context *ctx, struct rte_jobstats *job); /** + * Mark that *job* finished its execution, but time of this work will be skipped + * and added to management time. + * + * @param job + * Job object. + * + * @return + * 0 on success + * -EINVAL if job is NULL or job was not started (it have no context). + */ +int +rte_jobstats_abort(struct rte_jobstats *job); + +/** * Mark that *job* finished its execution. Context in which it was executing * will receive stat update. After this function call *job* object is ready to * be executed in other context. diff --git a/lib/librte_jobstats/rte_jobstats_version.map b/lib/librte_jobstats/rte_jobstats_version.map index cb01bfd..e3b21ca 100644 --- a/lib/librte_jobstats/rte_jobstats_version.map +++ b/lib/librte_jobstats/rte_jobstats_version.map @@ -17,3 +17,10 @@ DPDK_2.0 { local: *; }; + +DPDK_2.3 { + global: + + rte_jobstats_abort; + +} DPDK_2.0; -- 1.9.1
[dpdk-dev] [PATCH v2 1/1] jobstats: added function abort for job
This patch adds new function rte_jobstats_abort. It marks *job* as finished and time of this work will be add to management time instead of execution time. This function should be used instead of rte_jobstats_finish if condition occurs, condition is defined by the application for example when receiving n>0 packets. v2: * removed redundant field Signed-off-by: Marcin Kerlin --- lib/librte_jobstats/rte_jobstats.c | 20 lib/librte_jobstats/rte_jobstats.h | 14 ++ lib/librte_jobstats/rte_jobstats_version.map | 7 +++ 3 files changed, 41 insertions(+) diff --git a/lib/librte_jobstats/rte_jobstats.c b/lib/librte_jobstats/rte_jobstats.c index 2eaac0c..2b42050 100644 --- a/lib/librte_jobstats/rte_jobstats.c +++ b/lib/librte_jobstats/rte_jobstats.c @@ -170,6 +170,26 @@ rte_jobstats_start(struct rte_jobstats_context *ctx, struct rte_jobstats *job) } int +rte_jobstats_abort(struct rte_jobstats *job) +{ + struct rte_jobstats_context *ctx; + uint64_t now, exec_time; + + /* Some sanity check. */ + if (unlikely(job == NULL || job->context == NULL)) + return -EINVAL; + + ctx = job->context; + now = get_time(); + exec_time = now - ctx->state_time; + ADD_TIME_MIN_MAX(ctx, management, exec_time); + ctx->state_time = now; + job->context = NULL; + + return 0; +} + +int rte_jobstats_finish(struct rte_jobstats *job, int64_t job_value) { struct rte_jobstats_context *ctx; diff --git a/lib/librte_jobstats/rte_jobstats.h b/lib/librte_jobstats/rte_jobstats.h index de6a89a..c2b285f 100644 --- a/lib/librte_jobstats/rte_jobstats.h +++ b/lib/librte_jobstats/rte_jobstats.h @@ -237,6 +237,20 @@ int rte_jobstats_start(struct rte_jobstats_context *ctx, struct rte_jobstats *job); /** + * Mark that *job* finished its execution, but time of this work will be skipped + * and added to management time. + * + * @param job + * Job object. + * + * @return + * 0 on success + * -EINVAL if job is NULL or job was not started (it have no context). + */ +int +rte_jobstats_abort(struct rte_jobstats *job); + +/** * Mark that *job* finished its execution. Context in which it was executing * will receive stat update. After this function call *job* object is ready to * be executed in other context. diff --git a/lib/librte_jobstats/rte_jobstats_version.map b/lib/librte_jobstats/rte_jobstats_version.map index cb01bfd..e3b21ca 100644 --- a/lib/librte_jobstats/rte_jobstats_version.map +++ b/lib/librte_jobstats/rte_jobstats_version.map @@ -17,3 +17,10 @@ DPDK_2.0 { local: *; }; + +DPDK_2.3 { + global: + + rte_jobstats_abort; + +} DPDK_2.0; -- 1.9.1
[dpdk-dev] [PATCH V1 1/1] jobstats: added function abort for job
This patch adds new function rte_jobstats_abort. It marks *job* as finished and time of this work will be add to management time instead of execution time. This function should be used instead of rte_jobstats_finish if condition occure, condition is defined by the application for example when receiving n>0 packets. Signed-off-by: Marcin Kerlin --- lib/librte_jobstats/rte_jobstats.c | 22 ++ lib/librte_jobstats/rte_jobstats.h | 17 + lib/librte_jobstats/rte_jobstats_version.map | 7 +++ 3 files changed, 46 insertions(+) diff --git a/lib/librte_jobstats/rte_jobstats.c b/lib/librte_jobstats/rte_jobstats.c index 2eaac0c..b603125 100644 --- a/lib/librte_jobstats/rte_jobstats.c +++ b/lib/librte_jobstats/rte_jobstats.c @@ -170,6 +170,26 @@ rte_jobstats_start(struct rte_jobstats_context *ctx, struct rte_jobstats *job) } int +rte_jobstats_abort(struct rte_jobstats *job) +{ + struct rte_jobstats_context *ctx; + uint64_t now, exec_time; + + /* Some sanity check. */ + if (unlikely(job == NULL || job->context == NULL)) + return -EINVAL; + + ctx = job->context; + now = get_time(); + exec_time = now - ctx->state_time; + ADD_TIME_MIN_MAX(ctx, management, exec_time); + ctx->state_time = now; + job->context = NULL; + + return 0; +} + +int rte_jobstats_finish(struct rte_jobstats *job, int64_t job_value) { struct rte_jobstats_context *ctx; @@ -191,6 +211,7 @@ rte_jobstats_finish(struct rte_jobstats *job, int64_t job_value) * executed. */ now = get_time(); exec_time = now - ctx->state_time; + job->last_job_time = exec_time; ADD_TIME_MIN_MAX(job, exec, exec_time); ADD_TIME_MIN_MAX(ctx, exec, exec_time); @@ -269,5 +290,6 @@ void rte_jobstats_reset(struct rte_jobstats *job) { RESET_TIME_MIN_MAX(job, exec); + job->last_job_time = 0; job->exec_cnt = 0; } diff --git a/lib/librte_jobstats/rte_jobstats.h b/lib/librte_jobstats/rte_jobstats.h index de6a89a..9995319 100644 --- a/lib/librte_jobstats/rte_jobstats.h +++ b/lib/librte_jobstats/rte_jobstats.h @@ -90,6 +90,9 @@ struct rte_jobstats { uint64_t exec_cnt; /**< Execute count. */ + uint64_t last_job_time; + /**< Last job time */ + char name[RTE_JOBSTATS_NAMESIZE]; /**< Name of this job */ @@ -237,6 +240,20 @@ int rte_jobstats_start(struct rte_jobstats_context *ctx, struct rte_jobstats *job); /** + * Mark that *job* finished its execution, but time of this work will be skipped + * and added to management time. + * + * @param job + * Job object. + * + * @return + * 0 on success + * -EINVAL if job is NULL or job was not started (it have no context). + */ +int +rte_jobstats_abort(struct rte_jobstats *job); + +/** * Mark that *job* finished its execution. Context in which it was executing * will receive stat update. After this function call *job* object is ready to * be executed in other context. diff --git a/lib/librte_jobstats/rte_jobstats_version.map b/lib/librte_jobstats/rte_jobstats_version.map index cb01bfd..0ec0650 100644 --- a/lib/librte_jobstats/rte_jobstats_version.map +++ b/lib/librte_jobstats/rte_jobstats_version.map @@ -17,3 +17,10 @@ DPDK_2.0 { local: *; }; + +DPDK_2.3 { + global: + + rte_jobstats_abort; + +} DPDK_2.0; \ No newline at end of file -- 1 1.9.1
[dpdk-dev] [PATCH v3 5/5] doc: modify release notes and deprecation notice for table and pipeline
The LIBABIVER number is incremented for table and pipeline libraries. The release notes is updated and the deprecation announce is removed. Signed-off-by: Maciej Gajdzica Acked-by: Cristian Dumitrescu --- doc/guides/rel_notes/deprecation.rst | 3 --- doc/guides/rel_notes/release_2_2.rst | 6 -- lib/librte_pipeline/Makefile | 2 +- lib/librte_pipeline/rte_pipeline_version.map | 8 lib/librte_table/Makefile| 2 +- 5 files changed, 14 insertions(+), 7 deletions(-) diff --git a/doc/guides/rel_notes/deprecation.rst b/doc/guides/rel_notes/deprecation.rst index fa55117..2bf2df4 100644 --- a/doc/guides/rel_notes/deprecation.rst +++ b/doc/guides/rel_notes/deprecation.rst @@ -53,9 +53,6 @@ Deprecation Notices * librte_table LPM: A new parameter to hold the table name will be added to the LPM table parameter structure. -* librte_table: New functions for table entry bulk add/delete will be added - to the table operations structure. - * librte_table hash: Key mask parameter will be added to the hash table parameter structure for 8-byte key and 16-byte key extendible bucket and LRU tables. diff --git a/doc/guides/rel_notes/release_2_2.rst b/doc/guides/rel_notes/release_2_2.rst index 5687676..b46d2ae 100644 --- a/doc/guides/rel_notes/release_2_2.rst +++ b/doc/guides/rel_notes/release_2_2.rst @@ -98,6 +98,8 @@ ABI Changes * The LPM structure is changed. The deprecated field mem_location is removed. +* Added functions add/delete bulk to table and pipeline libraries. + Shared Library Versions --- @@ -122,7 +124,7 @@ The libraries prepended with a plus sign were incremented in this version. + librte_mbuf.so.2 librte_mempool.so.1 librte_meter.so.1 - librte_pipeline.so.1 + + librte_pipeline.so.2 librte_pmd_bond.so.1 + librte_pmd_ring.so.2 librte_port.so.1 @@ -130,6 +132,6 @@ The libraries prepended with a plus sign were incremented in this version. librte_reorder.so.1 librte_ring.so.1 librte_sched.so.1 - librte_table.so.1 + + librte_table.so.2 librte_timer.so.1 librte_vhost.so.1 diff --git a/lib/librte_pipeline/Makefile b/lib/librte_pipeline/Makefile index 15e406b..1166d3c 100644 --- a/lib/librte_pipeline/Makefile +++ b/lib/librte_pipeline/Makefile @@ -41,7 +41,7 @@ CFLAGS += $(WERROR_FLAGS) EXPORT_MAP := rte_pipeline_version.map -LIBABIVER := 1 +LIBABIVER := 2 # # all source are stored in SRCS-y diff --git a/lib/librte_pipeline/rte_pipeline_version.map b/lib/librte_pipeline/rte_pipeline_version.map index 8f25d0f..4cc86f6 100644 --- a/lib/librte_pipeline/rte_pipeline_version.map +++ b/lib/librte_pipeline/rte_pipeline_version.map @@ -29,3 +29,11 @@ DPDK_2.1 { rte_pipeline_table_stats_read; } DPDK_2.0; + +DPDK_2.2 { + global: + + rte_pipeline_table_entry_add_bulk; + rte_pipeline_table_entry_delete_bulk; + +} DPDK_2.1; diff --git a/lib/librte_table/Makefile b/lib/librte_table/Makefile index c5b3eaf..7f02af3 100644 --- a/lib/librte_table/Makefile +++ b/lib/librte_table/Makefile @@ -41,7 +41,7 @@ CFLAGS += $(WERROR_FLAGS) EXPORT_MAP := rte_table_version.map -LIBABIVER := 1 +LIBABIVER := 2 # # all source are stored in SRCS-y -- 1.9.1 -- Intel Shannon Limited Registered in Ireland Registered Office: Collinstown Industrial Park, Leixlip, County Kildare Registered Number: 308263 Business address: Dromore House, East Park, Shannon, Co. Clare This e-mail and any attachments may contain confidential material for the sole use of the intended recipient(s). Any review or distribution by others is strictly prohibited. If you are not the intended recipient, please contact the sender and delete all copies.
[dpdk-dev] [PATCH v3 4/5] ip_pipline: added cli commands for bulk add/delete to firewall pipeline
Added two new cli commands to firewall pipeline. Commands bulk add and bulk delete takes as argument a file with rules to add/delete. The file is parsed, and then rules are passed to backend functions which add/delete records from pipeline tables. Signed-off-by: Maciej Gajdzica Acked-by: Cristian Dumitrescu --- examples/ip_pipeline/pipeline/pipeline_firewall.c | 858 + examples/ip_pipeline/pipeline/pipeline_firewall.h | 14 + .../ip_pipeline/pipeline/pipeline_firewall_be.c| 157 .../ip_pipeline/pipeline/pipeline_firewall_be.h| 38 + 4 files changed, 1067 insertions(+) diff --git a/examples/ip_pipeline/pipeline/pipeline_firewall.c b/examples/ip_pipeline/pipeline/pipeline_firewall.c index f6924ab..4137923 100644 --- a/examples/ip_pipeline/pipeline/pipeline_firewall.c +++ b/examples/ip_pipeline/pipeline/pipeline_firewall.c @@ -51,6 +51,8 @@ #include "pipeline_common_fe.h" #include "pipeline_firewall.h" +#define BUF_SIZE 1024 + struct app_pipeline_firewall_rule { struct pipeline_firewall_key key; int32_t priority; @@ -73,6 +75,18 @@ struct app_pipeline_firewall { void *default_rule_entry_ptr; }; +struct app_pipeline_add_bulk_params { + struct pipeline_firewall_key *keys; + uint32_t n_keys; + uint32_t *priorities; + uint32_t *port_ids; +}; + +struct app_pipeline_del_bulk_params { + struct pipeline_firewall_key *keys; + uint32_t n_keys; +}; + static void print_firewall_ipv4_rule(struct app_pipeline_firewall_rule *rule) { @@ -256,6 +270,358 @@ app_pipeline_firewall_key_check_and_normalize(struct pipeline_firewall_key *key) } } +static int +app_pipeline_add_bulk_parse_file(char *filename, + struct app_pipeline_add_bulk_params *params) +{ + FILE *f; + char file_buf[BUF_SIZE]; + uint32_t i; + int status = 0; + + f = fopen(filename, "r"); + if (f == NULL) + return -1; + + params->n_keys = 0; + while (fgets(file_buf, BUF_SIZE, f) != NULL) + params->n_keys++; + rewind(f); + + if (params->n_keys == 0) { + status = -1; + goto end; + } + + params->keys = rte_malloc(NULL, + params->n_keys * sizeof(struct pipeline_firewall_key), + RTE_CACHE_LINE_SIZE); + if (params->keys == NULL) { + status = -1; + goto end; + } + + params->priorities = rte_malloc(NULL, + params->n_keys * sizeof(uint32_t), + RTE_CACHE_LINE_SIZE); + if (params->priorities == NULL) { + status = -1; + goto end; + } + + params->port_ids = rte_malloc(NULL, + params->n_keys * sizeof(uint32_t), + RTE_CACHE_LINE_SIZE); + if (params->port_ids == NULL) { + status = -1; + goto end; + } + + i = 0; + while (fgets(file_buf, BUF_SIZE, f) != NULL) { + char *str; + + str = strtok(file_buf, " "); + if (str == NULL) { + status = -1; + goto end; + } + params->priorities[i] = atoi(str); + + str = strtok(NULL, " ."); + if (str == NULL) { + status = -1; + goto end; + } + params->keys[i].key.ipv4_5tuple.src_ip = atoi(str)<<24; + + str = strtok(NULL, " ."); + if (str == NULL) { + status = -1; + goto end; + } + params->keys[i].key.ipv4_5tuple.src_ip |= atoi(str)<<16; + + str = strtok(NULL, " ."); + if (str == NULL) { + status = -1; + goto end; + } + params->keys[i].key.ipv4_5tuple.src_ip |= atoi(str)<<8; + + str = strtok(NULL, " ."); + if (str == NULL) { + status = -1; + goto end; + } + params->keys[i].key.ipv4_5tuple.src_ip |= atoi(str); + + str = strtok(NULL, " "); + if (str == NULL) { + status = -1; + goto end; + } + params->keys[i].key.ipv4_5tuple.src_ip_mask = atoi(str); + + str = strtok(NULL, " ."); + if (str == NULL) { + status = -1; + goto end; + } + params->keys[i].key.ipv4_5tuple.dst_ip = atoi(str)<<24; + + str = strtok(NULL, " ."); + if (str == NULL) { + status = -1; + goto end; + } + params->keys[i].key.ipv4_5tuple.dst_ip |= ato
[dpdk-dev] [PATCH v3 3/5] test_table: added check for bulk add/delete to acl table unit test
Added to acl table unit test check for bulk add and bulk delete. Signed-off-by: Maciej Gajdzica Acked-by: Cristian Dumitrescu --- app/test/test_table_acl.c | 166 ++ 1 file changed, 166 insertions(+) diff --git a/app/test/test_table_acl.c b/app/test/test_table_acl.c index e4e9b9c..fe8e545 100644 --- a/app/test/test_table_acl.c +++ b/app/test/test_table_acl.c @@ -253,6 +253,94 @@ parse_cb_ipv4_rule(char *str, struct rte_table_acl_rule_add_params *v) return 0; } +static int +parse_cb_ipv4_rule_del(char *str, struct rte_table_acl_rule_delete_params *v) +{ + int i, rc; + char *s, *sp, *in[CB_FLD_NUM]; + static const char *dlm = " \t\n"; + + /* + ** Skip leading '@' + */ + if (strchr(str, '@') != str) + return -EINVAL; + + s = str + 1; + + /* + * Populate the 'in' array with the location of each + * field in the string we're parsing + */ + for (i = 0; i != DIM(in); i++) { + in[i] = strtok_r(s, dlm, &sp); + if (in[i] == NULL) + return -EINVAL; + s = NULL; + } + + /* Parse x.x.x.x/x */ + rc = parse_ipv4_net(in[CB_FLD_SRC_ADDR], + &v->field_value[SRC_FIELD_IPV4].value.u32, + &v->field_value[SRC_FIELD_IPV4].mask_range.u32); + if (rc != 0) { + RTE_LOG(ERR, PIPELINE, "failed to read src address/mask: %s\n", + in[CB_FLD_SRC_ADDR]); + return rc; + } + + printf("V=%u, mask=%u\n", v->field_value[SRC_FIELD_IPV4].value.u32, + v->field_value[SRC_FIELD_IPV4].mask_range.u32); + + /* Parse x.x.x.x/x */ + rc = parse_ipv4_net(in[CB_FLD_DST_ADDR], + &v->field_value[DST_FIELD_IPV4].value.u32, + &v->field_value[DST_FIELD_IPV4].mask_range.u32); + if (rc != 0) { + RTE_LOG(ERR, PIPELINE, "failed to read dest address/mask: %s\n", + in[CB_FLD_DST_ADDR]); + return rc; + } + + printf("V=%u, mask=%u\n", v->field_value[DST_FIELD_IPV4].value.u32, + v->field_value[DST_FIELD_IPV4].mask_range.u32); + /* Parse n:n */ + rc = parse_port_range(in[CB_FLD_SRC_PORT_RANGE], + &v->field_value[SRCP_FIELD_IPV4].value.u16, + &v->field_value[SRCP_FIELD_IPV4].mask_range.u16); + if (rc != 0) { + RTE_LOG(ERR, PIPELINE, "failed to read source port range: %s\n", + in[CB_FLD_SRC_PORT_RANGE]); + return rc; + } + + printf("V=%u, mask=%u\n", v->field_value[SRCP_FIELD_IPV4].value.u16, + v->field_value[SRCP_FIELD_IPV4].mask_range.u16); + /* Parse n:n */ + rc = parse_port_range(in[CB_FLD_DST_PORT_RANGE], + &v->field_value[DSTP_FIELD_IPV4].value.u16, + &v->field_value[DSTP_FIELD_IPV4].mask_range.u16); + if (rc != 0) { + RTE_LOG(ERR, PIPELINE, "failed to read dest port range: %s\n", + in[CB_FLD_DST_PORT_RANGE]); + return rc; + } + + printf("V=%u, mask=%u\n", v->field_value[DSTP_FIELD_IPV4].value.u16, + v->field_value[DSTP_FIELD_IPV4].mask_range.u16); + /* parse 0/0xnn */ + GET_CB_FIELD(in[CB_FLD_PROTO], + v->field_value[PROTO_FIELD_IPV4].value.u8, + 0, UINT8_MAX, '/'); + GET_CB_FIELD(in[CB_FLD_PROTO], + v->field_value[PROTO_FIELD_IPV4].mask_range.u8, + 0, UINT8_MAX, 0); + + printf("V=%u, mask=%u\n", + (unsigned int)v->field_value[PROTO_FIELD_IPV4].value.u8, + v->field_value[PROTO_FIELD_IPV4].mask_range.u8); + return 0; +} /* * The format for these rules DO NOT need the port ranges to be @@ -393,6 +481,84 @@ setup_acl_pipeline(void) } } + /* Add bulk entries to tables */ + for (i = 0; i < N_PORTS; i++) { + struct rte_table_acl_rule_add_params keys[5]; + struct rte_pipeline_table_entry entries[5]; + struct rte_table_acl_rule_add_params *key_array[5]; + struct rte_pipeline_table_entry *table_entries[5]; + int key_found[5]; + struct rte_pipeline_table_entry *table_entries_ptr[5]; + struct rte_pipeline_table_entry entries_ptr[5]; + + parser = parse_cb_ipv4_rule; + for (n = 0; n < 5; n++) { + memset(&keys[n], 0, sizeof(struct rte_table_acl_rule_add_params)); + key_array[n] = &keys[n]; + + snprintf(line, sizeof(line), "%s", lines[n]); + printf("PARSING [%s]\n", line); + + ret = parser(line, &keys[n]); + if (ret != 0) { + RTE_LOG(ERR, PIPELINE, +
[dpdk-dev] [PATCH v3 2/5] pipeline: added bulk add/delete functions for table
Added functions for adding/deleting multiple records to table owned by pipeline. Signed-off-by: Maciej Gajdzica Signed-off-by: Marcin Kerlin Acked-by: Cristian Dumitrescu --- lib/librte_pipeline/rte_pipeline.c | 106 + lib/librte_pipeline/rte_pipeline.h | 64 ++ 2 files changed, 170 insertions(+) diff --git a/lib/librte_pipeline/rte_pipeline.c b/lib/librte_pipeline/rte_pipeline.c index bd700d2..56022f4 100644 --- a/lib/librte_pipeline/rte_pipeline.c +++ b/lib/librte_pipeline/rte_pipeline.c @@ -587,6 +587,112 @@ rte_pipeline_table_entry_delete(struct rte_pipeline *p, return (table->ops.f_delete)(table->h_table, key, key_found, entry); } +int rte_pipeline_table_entry_add_bulk(struct rte_pipeline *p, + uint32_t table_id, + void **keys, + struct rte_pipeline_table_entry **entries, + uint32_t n_keys, + int *key_found, + struct rte_pipeline_table_entry **entries_ptr) +{ + struct rte_table *table; + uint32_t i; + + /* Check input arguments */ + if (p == NULL) { + RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter is NULL\n", + __func__); + return -EINVAL; + } + + if (keys == NULL) { + RTE_LOG(ERR, PIPELINE, "%s: keys parameter is NULL\n", __func__); + return -EINVAL; + } + + if (entries == NULL) { + RTE_LOG(ERR, PIPELINE, "%s: entries parameter is NULL\n", + __func__); + return -EINVAL; + } + + if (table_id >= p->num_tables) { + RTE_LOG(ERR, PIPELINE, + "%s: table_id %d out of range\n", __func__, table_id); + return -EINVAL; + } + + table = &p->tables[table_id]; + + if (table->ops.f_add_bulk == NULL) { + RTE_LOG(ERR, PIPELINE, "%s: f_add_bulk function pointer NULL\n", + __func__); + return -EINVAL; + } + + for (i = 0; i < n_keys; i++) { + if ((entries[i]->action == RTE_PIPELINE_ACTION_TABLE) && + table->table_next_id_valid && + (entries[i]->table_id != table->table_next_id)) { + RTE_LOG(ERR, PIPELINE, + "%s: Tree-like topologies not allowed\n", __func__); + return -EINVAL; + } + } + + /* Add entry */ + for (i = 0; i < n_keys; i++) { + if ((entries[i]->action == RTE_PIPELINE_ACTION_TABLE) && + (table->table_next_id_valid == 0)) { + table->table_next_id = entries[i]->table_id; + table->table_next_id_valid = 1; + } + } + + return (table->ops.f_add_bulk)(table->h_table, keys, (void **) entries, + n_keys, key_found, (void **) entries_ptr); +} + +int rte_pipeline_table_entry_delete_bulk(struct rte_pipeline *p, + uint32_t table_id, + void **keys, + uint32_t n_keys, + int *key_found, + struct rte_pipeline_table_entry **entries) +{ + struct rte_table *table; + + /* Check input arguments */ + if (p == NULL) { + RTE_LOG(ERR, PIPELINE, "%s: pipeline parameter NULL\n", + __func__); + return -EINVAL; + } + + if (keys == NULL) { + RTE_LOG(ERR, PIPELINE, "%s: key parameter is NULL\n", + __func__); + return -EINVAL; + } + + if (table_id >= p->num_tables) { + RTE_LOG(ERR, PIPELINE, + "%s: table_id %d out of range\n", __func__, table_id); + return -EINVAL; + } + + table = &p->tables[table_id]; + + if (table->ops.f_delete_bulk == NULL) { + RTE_LOG(ERR, PIPELINE, + "%s: f_delete function pointer NULL\n", __func__); + return -EINVAL; + } + + return (table->ops.f_delete_bulk)(table->h_table, keys, n_keys, key_found, + (void **) entries); +} + /* * Port * diff --git a/lib/librte_pipeline/rte_pipeline.h b/lib/librte_pipeline/rte_pipeline.h index 59e0710..5459324 100644 --- a/lib/librte_pipeline/rte_pipeline.h +++ b/lib/librte_pipeline/rte_pipeline.h @@ -466,6 +466,70 @@ int rte_pipeline_table_entry_delete(struct rte_pipeline *p, struct rte_pipeline_table_entry *entry); /** + * Pipeline table entry add bulk + * + * @param p + * Handle to pipeline instance + * @param table_id + * Table ID (returned by previous invocation of pipeline table create) + * @param keys + * Array containing table entry k
[dpdk-dev] [PATCH v3 1/5] table: added bulk add/delete functions for table
New functions prototypes for bulk add/delete added to table API. New functions allows adding/deleting multiple records with single function call. For now those functions are implemented only for ACL table. For other tables these function pointers are set to NULL. Signed-off-by: Maciej Gajdzica Acked-by: Cristian Dumitrescu --- lib/librte_table/rte_table.h| 85 - lib/librte_table/rte_table_acl.c| 309 lib/librte_table/rte_table_array.c | 2 + lib/librte_table/rte_table_hash_ext.c | 4 + lib/librte_table/rte_table_hash_key16.c | 4 + lib/librte_table/rte_table_hash_key32.c | 4 + lib/librte_table/rte_table_hash_key8.c | 8 + lib/librte_table/rte_table_hash_lru.c | 4 + lib/librte_table/rte_table_lpm.c| 2 + lib/librte_table/rte_table_lpm_ipv6.c | 2 + lib/librte_table/rte_table_stub.c | 2 + 11 files changed, 420 insertions(+), 6 deletions(-) diff --git a/lib/librte_table/rte_table.h b/lib/librte_table/rte_table.h index c13d40d..720514e 100644 --- a/lib/librte_table/rte_table.h +++ b/lib/librte_table/rte_table.h @@ -154,6 +154,77 @@ typedef int (*rte_table_op_entry_delete)( void *entry); /** + * Lookup table entry add bulk + * + * @param table + * Handle to lookup table instance + * @param key + * Array containing lookup keys + * @param entries + * Array containing data to be associated with each key. Every item in the + * array has to point to a valid memory buffer where the first entry_size + * bytes (table create parameter) are populated with the data. + * @param n_keys + * Number of keys to add + * @param key_found + * After successful invocation, key_found for every item in the array is set + * to a value different than 0 if the current key is already present in the + * table and to 0 if not. This pointer has to be set to a valid memory + * location before the table entry add function is called. + * @param entries_ptr + * After successful invocation, array *entries_ptr stores the handle to the + * table entry containing the data associated with every key. This handle can + * be used to perform further read-write accesses to this entry. This handle + * is valid until the key is deleted from the table or the same key is + * re-added to the table, typically to associate it with different data. This + * pointer has to be set to a valid memory location before the function is + * called. + * @return + * 0 on success, error code otherwise + */ +typedef int (*rte_table_op_entry_add_bulk)( + void *table, + void **keys, + void **entries, + uint32_t n_keys, + int *key_found, + void **entries_ptr); + +/** + * Lookup table entry delete bulk + * + * @param table + * Handle to lookup table instance + * @param key + * Array containing lookup keys + * @param n_keys + * Number of keys to delete + * @param key_found + * After successful invocation, key_found for every item in the array is set + * to a value different than 0if the current key was present in the table + * before the delete operation was performed and to 0 if not. This pointer + * has to be set to a valid memory location before the table entry delete + * function is called. + * @param entries + * If entries pointer is NULL, this pointer is ignored for every entry found. + * Else, after successful invocation, if specific key is found in the table + * (key_found is different than 0 for this item after function call is + * completed) and item of entry array points to a valid buffer (entry is set + * to a value different than NULL before the function is called), then the + * first entry_size bytes (table create parameter) in *entry store a copy of + * table entry that contained the data associated with the current key before + * the key was deleted. + * @return + * 0 on success, error code otherwise + */ +typedef int (*rte_table_op_entry_delete_bulk)( + void *table, + void **keys, + uint32_t n_keys, + int *key_found, + void **entries); + +/** * Lookup table lookup * * @param table @@ -213,12 +284,14 @@ typedef int (*rte_table_op_stats_read)( /** Lookup table interface defining the lookup table operation */ struct rte_table_ops { - rte_table_op_create f_create; /**< Create */ - rte_table_op_free f_free; /**< Free */ - rte_table_op_entry_add f_add; /**< Entry add */ - rte_table_op_entry_delete f_delete; /**< Entry delete */ - rte_table_op_lookup f_lookup; /**< Lookup */ - rte_table_op_stats_read f_stats;/**< Stats */ + rte_table_op_create f_create; /**< Create */ + rte_table_op_free f_free; /**< Free */ + rte_table_op_entry_add f_add; /**< Entry add */ + rte_table_op_entry_delete f_delete; /**< Entry delete */ + rte_table_op_entry_add_bulk f_
[dpdk-dev] [PATCH v3 0/5] pipeline: add bulk add/delete functions for table
This patch adds bulk add/delete functions for tables used by pipelines. It allows for adding/deleting many rules to pipeline tables in one function call. It is particulary useful for firewall pipeline which is using ACL table. After every add or delete, table is rebuild which leads to very long times when trying to add/delete many entries. v2: * Incremented the LIBABIVER number * Updated release notes * Removed deprecation announce v3: * Updated a Doxygen comment Acked-by: Cristian Dumitrescu Maciej Gajdzica (5): table: added bulk add/delete functions for table pipeline: added bulk add/delete functions for table test_table: added check for bulk add/delete to acl table unit test ip_pipline: added cli commands for bulk add/delete to firewall pipeline doc: modify release notes and deprecation notice for table and pipeline app/test/test_table_acl.c | 166 doc/guides/rel_notes/deprecation.rst | 3 - doc/guides/rel_notes/release_2_2.rst | 6 +- examples/ip_pipeline/pipeline/pipeline_firewall.c | 858 + examples/ip_pipeline/pipeline/pipeline_firewall.h | 14 + .../ip_pipeline/pipeline/pipeline_firewall_be.c| 157 .../ip_pipeline/pipeline/pipeline_firewall_be.h| 38 + lib/librte_pipeline/Makefile | 2 +- lib/librte_pipeline/rte_pipeline.c | 106 +++ lib/librte_pipeline/rte_pipeline.h | 64 ++ lib/librte_pipeline/rte_pipeline_version.map | 8 + lib/librte_table/Makefile | 2 +- lib/librte_table/rte_table.h | 85 +- lib/librte_table/rte_table_acl.c | 309 lib/librte_table/rte_table_array.c | 2 + lib/librte_table/rte_table_hash_ext.c | 4 + lib/librte_table/rte_table_hash_key16.c| 4 + lib/librte_table/rte_table_hash_key32.c| 4 + lib/librte_table/rte_table_hash_key8.c | 8 + lib/librte_table/rte_table_hash_lru.c | 4 + lib/librte_table/rte_table_lpm.c | 2 + lib/librte_table/rte_table_lpm_ipv6.c | 2 + lib/librte_table/rte_table_stub.c | 2 + 23 files changed, 1837 insertions(+), 13 deletions(-) -- 1.9.1 -- Intel Shannon Limited Registered in Ireland Registered Office: Collinstown Industrial Park, Leixlip, County Kildare Registered Number: 308263 Business address: Dromore House, East Park, Shannon, Co. Clare This e-mail and any attachments may contain confidential material for the sole use of the intended recipient(s). Any review or distribution by others is strictly prohibited. If you are not the intended recipient, please contact the sender and delete all copies.