Cross-compiling a custom Net-SNMP agent

Building the default agents in Net-SNMP is quite easy if you’re using tools such as Buildroot, and even when building directly from the sources is not a problem. However, is not that easy if you want to cross-build a custom agent inside Net-SNMP.

This procedure worked for me, but keep in mind that it was not a clean procedure since it involves modifying the generated Makefiles, so every time that you ./configure you will loose your changes.

First, let’s export common environment variables that make our life easier:

export HOST=arm-linux
export BUILD=i386-linux
export PREFIX=/home/paguilar/rootfs

Download

Net-SNMP
Package: net-snmp-5.6.2.1

Configure

./configure \
--prefix=$PREFIX \
--host=$HOST \
--build=$BUILD \
--exec-prefix=$PREFIX/usr \
--sysconfdir=/etc \
--enable-static \
--enable-shared \
--with-persistent-directory=/var/lib/snmp \
--disable-static \
--with-defaults \
--enable-mini-agent \
--without-rpm \
--with-logfile=none \
--without-kmem-usage \
--enable-as-needed \
--disable-debugging \
--without-perl-modules \
--disable-embedded-perl \
--disable-perl-cc-checks \
--disable-scripts \
--with-default-snmp-version="1" \
--enable-silent-libtool \
--enable-mfd-rewrites \
--with-sys-contact="root@localhost" \
--with-sys-location="Unknown" \
--with-mib-modules="host ucd-snmp/dlmod examples/example my_mib/custom_mib" \
--with-out-transports="Unix" \
--with-endianness=little \
--without-openssl \
--disable-manuals \
--with-cflags="-I$PREFIX/usr/include -I$PREFIX/usr/include/glib-2.0 -I$PREFIX/usr/lib/glib-2.0/include" \
--with-ldflags="-L$PREFIX/lib" \
--with-mibdirs="$HOME/.snmp/mibs:/usr/share/snmp/mibs"

Instead of using the –with-cflags and –with-ldflags, you can define the CFLAGS and LDFLAGS:

CFLAGS="-I$PREFIX/usr/include -I$PREFIX/usr/include/glib-2.0 -I$PREFIX/usr/lib/glib-2.0/include" \
LDFLAGS="-L$PREFIX/usr/lib -pthread -lgobject-2.0 -lgmodule-2.0 -lgthread-2.0 -lglib-2.0 -lxml2 -lintl -lsqlite3 -lntxipc -lntxmisc" \

The custom agent must be located inside the agent/mibgroup directory. In this case, create the directory agent/mibgroup/my_mib and write here the agent sources:

mkdir agent/mibgroup/my_mib
vi agent/mibgroup/my_mib/custom_mib.c
vi agent/mibgroup/my_mib/custom_mib.h

If these agent source use only libc it wouldn’t be an issue. But they use other libraries such as Glib2, SQLite3 and libxml2, thus we have to include these libraries by using the –with-cflags and –with-ldflags options or the CFLAGS and LDFLAGS environment variables.

However, when building, the linker didn’t find the GLib2, sqlite3 and libmlx2 shared libraries even though I specified the paths as above…
I got this kind of errors:

/home/paguilar/net-snmp-5.6.2.1/agent/.libs/libnetsnmpmibs.so: undefined reference to `sqlite3_close'
/home/paguilar/net-snmp-5.6.2.1/agent/.libs/libnetsnmpmibs.so: undefined reference to `sqlite3_exec'
/home/paguilar/net-snmp-5.6.2.1/agent/.libs/libnetsnmpmibs.so: undefined reference to `sqlite3_errmsg'
/home/paguilar/net-snmp-5.6.2.1/agent/.libs/libnetsnmpmibs.so: undefined reference to `sqlite3_open'
collect2: ld returned 1 exit status
Makefile:245: recipe for target 'snmptrapd' failed
make[1]: *** [snmptrapd] Error 1
make[1]: Leaving directory '/home/paguilar/net-snmp-5.6.2.1/apps'
Makefile:567: recipe for target 'subdirs' failed
make: *** [subdirs] Error 1

For solving this issue in a dirty but fast way, modify the files agent/Makefile and apps/Makefile. Set the LDFLAGS variable to the following value:

LDFLAGS = -L/home/paguilar/rootfs/usr/lib -pthread -lgobject-2.0 -lgmodule-2.0 -lgthread-2.0 -lglib-2.0 -lxml2 -lintl -lsqlite3

In this way you can quickly build your custom SNMP agent inside Net-SNMP.

Missing requirements when building with Buildroot

Buildroot is a quite useful tool when working with small-to-medium embedded systems. It helps you to create the toolchain, the rootfs and, of course, building the kernel and hundreds of packages normally found in standard Linux distributions.

For using Buildroot you need several mandatory and optional requirements in your host machine. They’re listed in the Buildroot manual. However, there are some sub-requirements that aren’t mentioned since they belong to a global requirement. For example the package Thread/Queue.pm is a Perl module that belongs to the global requirement Perl.

The lack of one of these packages can cause building errors that can confuse new users since it could not be clear if it’s an issue with the package that it’s been built or if it’s an issue with the host machine that is missing something.

Normally, when you see an error like the following, you can be sure that there is a missing Perl module in your host machine:

Can't locate Thread/Queue.pm in @INC (you may need to install the Thread::Queue module) (@INC contains: /home/projects/sunxi/buildroot-2015.08.1/output/host/usr/share/automake-1.15 /home/projects/sunxi/buildroot-2015.08.1/output/host/usr/lib/perl /usr/local/lib64/perl5 /usr/local/share/perl5 /usr/lib64/perl5/vendor_perl /usr/share/perl5/vendor_perl /usr/lib64/perl5 /usr/share/perl5 .) at /home/projects/sunxi/buildroot-2015.08.1/output/host/usr/bin/automake line 55.
BEGIN failed--compilation aborted at /home/projects/sunxi/buildroot-2015.08.1/output/host/usr/bin/automake line 58.
autoreconf: /home/projects/sunxi/buildroot-2015.08.1/output/host/usr/bin/automake failed with exit status: 2
package/pkg-generic.mk:146: recipe for target '/home/projects/sunxi/buildroot-2015.08.1/output/build/alsa-lib-1.0.29/.stamp_configured' failed
make[1]: *** [/home/projects/sunxi/buildroot-2015.08.1/output/build/alsa-lib-1.0.29/.stamp_configured] Error 2
Makefile:36: recipe for target '_all' failed
make: *** [_all] Error 2

In this example, Buildroot fails to build the ALSA lib since it requires the Perl module Thread/Queue.pm that is missing.
You can easily install it, assuming that you already installed the CPAN module, by typing:

$ cpan
cpan shell -- CPAN exploration and modules installation (v2.00)
Enter 'h' for help.

cpan[1]> install Thread/Queue.pm

This kind of issues can also be present with other requirements, such as Python that can be installed with the pip utility.

Generally speaking, when you see a message like this one, there’s a good chance that the problem is a missing requirement:

autoreconf: /home/projects/sunxi/buildroot-2015.08.1/output/host/usr/bin/automake failed with exit status: 2
package/pkg-generic.mk:146: recipe for target '/home/projects/sunxi/buildroot-2015.08.1/output/build/alsa-lib-1.0.29/.stamp_configured' failed
make[1]: *** [/home/projects/sunxi/buildroot-2015.08.1/output/build/alsa-lib-1.0.29/.stamp_configured] Error 2

Communicating to a serial interface of an embedded Linux device using kermit

I have used kermit for connecting to serial interfaces for several years and it has always worked as expected. Even for sending a kernel image to U-Boot using the zmodem protocol (yes, it took ages, but there was no Ethernet) has worked quite well.

Recently, a friend that is new to embedded Linux ask me how to connect to a serial interface, so this is a small and simple guide on how to do it.

Just as an intro, a summary of what is kermit taken from the Fedora repo:

C-Kermit is a combined serial and network communication software package offering a consistent, medium-independent, cross-platform approach to connection establishment, terminal sessions, file transfer and management, character-set translation, and automation of communication tasks.

Installation
If you have Fedora, CentOS, SuSE or other rpm based distribution

yum install ckermit

If you have Debian, Mint, Ubuntu or other deb based distribution

apt-get install ckermit

Configuration
Create the configuration file .kermrc in your home directory. These parameters are normally right for most systems. I’ve used it for SH4 and ARM based devices:

set line /dev/ttyUSB0
set speed 115200
set carrier-watch off
set handshake none
set flow-control none
robust
set file type bin
set file name lit
set rec pack 1000
set send pack 1000
set window 5
connect

The most important parameters here are the line parameter that indicates the serial device and the speed parameters that is it’s baud rate. If you have an USB-to-serial interface converter your device will be /dev/ttyUSBx where x is normally 0, but it depends on how may USB-to-serial converters you have. The same happens if you have a normal serial cable, except that your device will be named /dev/ttySx, where x is normally 0.

Permissions
Add your user to the dialout group in the /etc/group file

dialout:x:18:paguilar

Logout and login again. This is needed since the group to which a user belongs are assigned when the user logs in.

Execution
Open a shell and execute kermit. The output should be something like this:

Connecting to /dev/ttyUSB0, speed 115200
 Escape character: Ctrl-\ (ASCII 28, FS): enabled
Type the escape character followed by C to get back,
or followed by ? to see other options.
----------------------------------------------------

By default, kermit searches the file .kermrc in your home directory. If you have several kermit config files (may be because you have several boards configured differently), you can specify it:

kermit /home/paguilar/.custom_kermrc

If there are problems like the wrong serial interface, you may see a message like this one:

?SET SPEED has no effect without prior SET LINE
Sorry, you must SET LINE or SET HOST first
C-Kermit 9.0.302 OPEN SOURCE:, 20 Aug 2011, for Linux (64-bit)
 Copyright (C) 1985, 2011,
  Trustees of Columbia University in the City of New York.
Type ? or HELP for help.

You can also have this problem if there is a lock file. This error happens if you try to access the serial interface whilst another process is already using it. It can also happen if you kill a previous kermit session when it was connected to the serial interface.
In these cases you have to remove the lock file and execute kermit again.

Assuming that everything went right and you happily used a busybox shell or similar you can disconnect from kermit by typing Ctrl-\ + q

Just to be clear, the escape control sequence is Ctrl and backslash at the same time, then you enter the desired character.
For example, if you are in your board’s shell, for connecting to the kermit shell just type Ctrl-\ + c, then enter connect to go back to your board’s shell.

That’s it.