How to compile a DPDK application as a library - dpdk

I have a program using DPDK and I am compiling it using the Makefile provided in the examples.
If i compile the program as an APP (as describe here), all goes
well.
However, my code is part of a larger project, for which the use of a
separate makefile causes a lot of troubles.
So I bundled my code in a library, as described in the same page.
The program that calls the functions in the library (to initialize the
EAL) is getting this error:
MBUF: error setting mempool handler
Cannot init mbuf pool
It seems that, when the application is compiled as a library, the EAL cannot be initialized correctly.
I report here the steps to reproduce the problem using the l2fwd example.
Background
I built DPDK from source as described here, and I have one ethernet interface bound to DPDK drivers:
$ $RTE_SDK/usertools/dpdk-devbind.py --status |head -n4
Network devices using DPDK-compatible driver
============================================
0000:01:00.0 '82599ES 10-Gigabit SFI/SFP+ Network Connection 10fb' drv=igb_uio unused=ixgbe
Run the l2fwd example
Copy the example folder first and then run the example:
$ cp -r $RTE_SDK/examples/l2fwd $RTE_SDK/examples/l2fwd-lib/
$ cd $RTE_SDK/examples/l2fwd
$ make
CC main.o
LD l2fwd
INSTALL-APP l2fwd
INSTALL-MAP l2fwd.map
$ sudo ./build/l2fwd -l 0-3 -- -p 0x1
Port statistics ====================================
Statistics for port 0 ------------------------------
Packets sent: 0
Packets received: 0
Packets dropped: 0
Aggregate statistics ===============================
Total packets sent: 0
Total packets received: 0
Total packets dropped: 0
====================================================
It works!
Build the same example as a library
cd ../l2fwd-lib/
mv main.c l2fwd.c
Modify l2fwd.c, adding #include "l2fwd.h" on top and replacing
int main(int argc, char **argv)
with
int start(int argc, char **argv)
Create the header file l2fwd.h with the library interface:
int start(int argc, char **argv);
Modify the Makefile as described in the docs:
APP = l2fwd ---> LIB = libl2fwd.a
SRCS-y := main.c ---> SRCS-y := l2fwd.c
include $(RTE_SDK)/mk/rte.extapp.mk ---> include $(RTE_SDK)/mk/rte.extlib.mk
Compile the library:
$ make
CC l2fwd.o
AR libl2fwd.a
INSTALL-LIB libl2fwd.a
Write a program that uses the library. Create the main.c file with just these 2 lines:
#include "l2fwd.h"
int main (int argc, char **argv) { start(argc, argv); }
compile it (with all the needed libraries):
gcc -L build/lib/ -L $RTE_SDK/build/lib/ main.c -o main.o -l l2fwd -l dpdk -l numa -pthread -l dl
Finally, run it with the same parameters used earlier:
$ sudo ./main.o -l 0-3 -- -p 0x1
EAL: Detected 40 lcore(s)
EAL: Detected 2 NUMA nodes
EAL: Multi-process socket /var/run/dpdk/rte/mp_socket
EAL: Probing VFIO support...
MAC updating enabled
EAL: Error - exiting with code: 1
Cause: No Ethernet ports - bye
In this case, the EAL cannot be initialized properly (the ethernet port is still bound to the DPDK drivers).
Edit 1
According to #Andriy Berestovskyy, the linker --whole-archive option is needed when linking DPDK libraries. This solves the problem with the examples.
However, my program is facing a different problem now. I need to use a custom build system, so I am linking the DPDK application as a library. During execution I get the error:
MBUF: error setting mempool handler
mempool/dpaa2: Not a valid dpaa2 buffer pool
Looks like it is using the dpaa2 driver, that is the wrong driver (my NIC is using igb_uio). Any hints on why this is happening? The same code worked when compiled as a DPDK app, so it is probably related to the linking process.
Edit 2
This error is due to the fact that I compiled DPDK with the
CONFIG_RTE_BUILD_SHARED_LIB=y option. When DPDK is built as a shared library, the driver must be explicitly set using the -d EAL command line option.
I re-compiled DPDK with CONFIG_RTE_BUILD_SHARED_LIB=n and the problem was solved.

compile it (with all the needed libraries):
gcc -L build/lib/ -L $RTE_SDK/build/lib/ main.c -o main.o -l l2fwd -l dpdk -l numa -pthread -l dl
I guess the issue is in this step. DPDK uses link-level constructors (i.e. __attribute__((constructor))). See the definition of RTE_INIT() for example. Also there are callbacks etc. etc.
So to properly link with DPDK we have to:
either use an rte.app.mk in the Makefile (see Development Kit Build System)
or in case we need to use a custom build system, we need to link DPDK libraries after the --whole-archive option.

I got the similar issue and as mentioned in here, I used -d option to link the libray "-d /usr/lib64/librte_mempool_ring.so". It worked.

Related

Linux perf not resolving symbols

I am using Openwrt having linux Kernel version 4.14 .
I have compiled my C++ code with -fno-omit-frame-pointer and with debug -g3. For the compiled binary and all dependent libraries ,objdump -t list the symbols. ulimit-a output is also good, have set most of component to unlimited or a to higher value.
Executing perf with command perf record -F 99 -p pid --call-graph dwarf -g and perf record -F 99 -p <pid> -g
perf report resolves all the kernel symbols ,but NOT getting resolve the user space symbols.
Am I missing something ? How to get the user space symbols resolved?
compiling perf tool with libelf and libdw support resolved the issue .
Able to get userspace symbols also resolved along with Kernel.

Where is dmalloc in openSUSE?

Which openSUSE rpm contains dmalloc? No repository have it. Tried to build it from src.rpm found for SLE 12. However it does not contain libdmalloc* libraries. How to do LD_PRELOAD="libdmalloc.so" ./my_program? Or it is not necessary?
Works without LD_PRELOAD, seems not necessary any more, just simple:
1) eval `dmalloc -d 0 -l leak.log -p log-non-free`
2) ./my_program
However program should be built and linked with dmalloc:
#include <dmalloc.h>
Link:
$ g++ -L/usr/lib64 -ldmalloc ...

"sh: ./<file> not found" error when trying to execute a file

I've come across a weirdest problem I ever met. I'm cross-compiling an app for ARM CPU with Linux on-board. I'm using buildroot, and all goes well until I'm trying to run the application on the target: I'm getting -sh: ./hw: not found. E.g.:
$ cat /tmp/test.cpp
#include <cstdio>
#include <vector>
int main(int argc, char** argv){
printf("Hello Kitty!\n");
return 0;
}
$ ./arm-linux-g++ -march=armv7-a /tmp/test.cpp -o /tftpboot/hw
load the executable to the target; then issuing on the target:
# ./hw
-sh: ./hw: Permission denied
# chmod +x ./hw
# ./hw
-sh: ./hw: not found
# ls -l ./hw
-rwxr-xr-x 1 root root 6103 Jan 1 03:40 ./hw
There's more to it: upon building with distro compiler, like arm-linux-gnueabi-g++ -march=armv7-a /tmp/test.cpp -o /tftpboot/hw, the app runs fine!
I compared executables through readelf -a -W /tftpboot/hw, but didn't notice much defference. I pasted both outputs here. The only thing I noticed, are lines Version5 EABI, soft-float ABI vs Version5 EABI. I tried removing the difference by passing either of -mfloat-abi=softfp and -mfloat-abi=soft, but compiler seems to ignore it. I suppose though, this doesn't really matter, as compiler doesn't even warn.
I also thought, perhaps sh outputs this error if an executable is incompatible in some way. But on my host PC I see another error in this case, e.g.:
$ sh /tftpboot/hw
/tftpboot/hw: 1: /tftpboot/hw: Syntax error: word unexpected (expecting ")")
sh prints this weird error because it is trying to run your program as a shell script!
Your error ./hw: not found is probably caused by the dynamic linker (AKA ELF interpreter) not being found. Try compiling it as a static program with -static or running it with your dynamic loader: # /lib/ld-linux.so.2 ./hw or something like that.
If the problem is that the dynamic loader is named differently in your tool-chain and in your runtime environment you can fix it:
In the runtime environment: with a symbolic link.
In the tool-chain: use -Wl,--dynamic-linker=/lib/ld-linux.so.2

dtrace on linux does not always remove userland probes at program exit -- why?

(See end of this post if you want to see how I installed dtrace - for now I'll assume you already have it installed)
I made a custom probe with no problems at all by following these steps:
A. Create thing.d with my probe definition
provider thing {
probe test();
};
B. Create a simple main.cpp
#include "thing.h"
int main()
{
// Fire my probe
THING_TEST();
// Something to prevent immediate exit
for(;;)
sleep(1);
// Bye
return 0;
}
C. Compile (but don't link) main.cpp. Note how you must define _DTRACE_VERSION or else your probes will be commented out in thing.h.
g++ -D _DTRACE_VERSION -c main.cpp -o main.o
D. Build the probe object file (note that you must include main.o as part of this)
dtrace -G -s thing.d -o thing.o main.o
E. Link it all up
g++ main.o thing.o -o thing
Here's the problem: Run the app, and terminate with CTRL-C (obviously the app won't stop by itself because of the infinite loop...).
In fact, do this a few times.
Now, from a superuser terminal:
# dtrace -l | grep thing
322991 thing28217 thing main test
322992 thing28403 thing main test
322994 thing28636 thing main test
These guys are just hanging around... It's like they never got de-registered or something.
I've run "ps" to see if there are any procs with those pids (28217, 28403, 28636) and nope, nothing there.
INTERESTINGLY, if I remove the infinite loop from main.cpp (the sleep() loop) and just let the app immediately exit, then the probes are properly removed. So it seems like the issue has to do with CTRL-C being detected inside of sleep() - perhaps some kind of atexit() handler isn't being called?
Here's my system info:
$ uname -a
Linux beavis 3.5.0-26-generic #42-Ubuntu SMP Fri Mar 8 23:18:20 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux
$ g++ --version
g++ (Ubuntu/Linaro 4.7.2-2ubuntu1) 4.7.2
DTRACE INSTALLATION
I am not using the default dtrace that comes with Ubuntu, but rather the dtrace4linux stuff which I installed like this:
http://askubuntu.com/questions/60940/how-do-i-install-dtrace
NOTE: I am using the latest version from Paul Fox's site:
ftp://crisp.dyndns-server.com/pub/release/website/dtrace/dtrace-20130317.tar.bz2

Linking an application to libbz2.so.1 rather than libbz2.so.1.0

Here's the current situation I'm in:
I want to distribute a binary app on Linux that would run on several distros (not all of them, just the main ones matter at the moment, let's focus on Ubuntu and Fedora for the sake of this discussion). The app in question links to libbz2 for some of its work. A simple "Hello World" will illustrate the situation :
/* main.cpp */
#include <iostream>
int main(int argc, char* argv[])
{
std::cout << "Hello World!\n";
return 0;
}
The app is built as such :
g++ -lbz2 -o test.bin main.cpp
My build system is on Ubuntu. When I perform a check with ldd on the resulting binary, it lists libbz2.so.1.0 as a runtime dependency. When I take this app to a Fedora machine, the app doesn't run and ldd reveals that it can't find libbz2.so.1.0. Fedora only has libbz2.so.1 and libbz2.so.1.0.4, but not libbz2.so.1.0.
Red Hat's Bugzilla database reveals that this behavior is not a bug, but a feature. I don't really need libbz2.so.1.0, and I would be satisfied with simply linking to libbz2.so.1, but I have yet to figure out how.
I have seen a similar question asked here previously, but the accepted answer (You can pass the actual .so file instead of -l on the linker command line) doesn't seem to work. I tried building with the following command :
g++ /lib/libbz2.so.1 -o test.bin main.cpp
However, ldd still mentions that the app depends on libbz2.so.1.0, even though I passed the full name to g++.
Now, the question is, is there a way on Ubuntu to build the app to have it depend only on libbz2.so.1 rather than on libbz2.so.1.0?
Thanks.
Here's a bit of background to explain what got linked. On ELF platforms the -L and -l flags you pass only locate the binary at link time. If the linker linker determines that a library is required it generates a reference to the SONAME in that binary, regardless of what it was called. For example:
$ objdump -p /lib64/libbz2.so.1 | grep SONAME
SONAME libbz2.so.1
So regardless of what libbz2 is named, that is what will show up as a dependency. Again by example, doing something totally whacked:
$ ln -s /lib64/libbz2.so.1 libblah.so
$ g++ t.C -L. -l blah
You have the apparency of having linked to libblah but because its the SONAME in that binary that matters, your dependency is still this libbz2.so.1
$ ldd a.out | grep bz2
libbz2.so.1 => /lib64/libbz2.so.1 (0x00002b3d1a000000)
Other than the -static trickery (which can break things in interesting ways), there is not easy way out of the mess (ideally the library would do nice symbol versioning like glibc and never or rarely change its SONAME).
Why don't you just link statically instead?
I have done that in the past for builds on Ubuntu and deployment on RHEL which works just fine using static builds.