Additional Linux Details

The tutorial gives most information required for getting started on a Linux machine. Some additional information is given here.

Detailed dependency installation info

You need to have cmake version at least 3.14 installed. It is available in Ubuntu 19.04 and later.

To install on Ubuntu 16.04 or 18.04, follow the instructions here: https://blog.kitware.com/ubuntu-cmake-repository-now-available/

It is also possible to install it via snap:

sudo snap install cmake --classic

When using it, you might need to replace cmake with snap run cmake. If uninstalling the default cmake, the snap-installed version should be used by default after reboot.

Optional dependencies (for development and documentation of the p-net stack):

sudo apt install -y \
    clang-tools \
    clang-format-10 \
    doxygen \
    graphviz

Run tests and generate documentation

Run tests (if you told cmake to configure it):

cmake --build build --target check

Run a single test file:

build/pf_test --gtest_filter=CmrpcTest.CmrpcConnectReleaseTest

Create Doxygen documentation:

cmake --build build --target docs

The Doxygen documentation ends up in build/html/index.html

See the “Writing documentation” page if you would like to install the toolchain to build the entire Sphinx documentation.

The clang static analyzer can also be used if installed. Create a new build directory by running:

scan-build cmake -B build.scan-build -S p-net
scan-build cmake --build build

Setting Linux ephemeral port range

This is the range of random source ports used when sending UDP messages. Profinet requires that the UDP source port should be >= 0xC000, which is 49152 in decimal numbers.

To change the ephemeral port range:

echo "49152 60999" > /proc/sys/net/ipv4/ip_local_port_range

This should typically be done at system start up.

File size and memory usage on Linux

The resulting file size of the sample application binary is heavily dependent on the compile time options, for example whether to include debug information. In this example we use:

BUILD_SHARED_LIBS ON
CMAKE_BUILD_TYPE Release
LOG_LEVEL Warning
PNET_MAX_AR 2
PNET_MAX_SLOTS 5
PNET_MAX_SUBSLOTS 3

To get an estimate of the binary size, partially link it (use release, without standard libraries):

p-net/build$ make all
p-net/build$ /usr/bin/cc -O3 -DNDEBUG CMakeFiles/pn_dev.dir/sample_app/sampleapp_common.o CMakeFiles/pn_dev.dir/src/ports/linux/sampleapp_main.o -o pn_dev libprofinet.a -nostdlib -r

Resulting size:

p-net/build$ size pn_dev
   text         data     bss     dec     hex filename
244481            72       8  244561   3bb51 pn_dev

See https://linux.die.net/man/1/size for information on how to use the command. Also the rt-kernel page in this documentation has some description on how to interpret the output.

The size of the p-net stack can be estimated from the size of libprofinet, built with the options given above:

p-net/build$ size libprofinet.so
   text         data     bss     dec     hex filename
230888          3304       8  234200   392d8 libprofinet.so

An estimate of the p-net RAM usage can be made from the size of the pnet_t struct. The sample application has a command line option to show this value, for the used compile time options (for example the maximum number of modules allowed).

Debug intermittent segmentation faults during tests on Linux

Enable core dumps:

ulimit -c unlimited

Run a test case until the problem occurs (in the build directory):

while ./pf_test --gtest_filter=DiagTest.DiagRunTest; do :; done

Study the resulting core:

gdb pf_test core

SNMP (Conformance class B)

Conformance class B requires SNMP support. Linux uses net-snmp as agent, see http://www.net-snmp.org/. The name of the SNMP agent binary is snmpd.

P-Net for Linux implements a Net-SNMP subagent that handles the Profinet mandatory MIB:s. Also see Network topology detection for information regarding SNMP.

Enable SNMP by setting PNET_OPTION_SNMP to ON in the p-net compilation options. Net-SNMP also needs to be installed. On Ubuntu you can install the required packages using:

sudo apt install -y snmpd libsnmp-dev

To show the installed version of snmpd, use:

snmpd -v

Change snmpd command line arguments

The p-net SNMP subagent will handle the system objects, so the default SNMP “system” module should be disabled by adding the snmpd argument -I -system_mib. Otherwise the subagent will complain about “registering pdu failed” at startup. If you use systemd init system (for example on Ubuntu Linux) you should change /lib/systemd/system/snmpd.service to read:

[Unit]
Description=Simple Network Management Protocol (SNMP) Daemon.
After=network.target
ConditionPathExists=/etc/snmp/snmpd.conf

[Service]
Type=simple
ExecStartPre=/bin/mkdir -p /var/run/agentx
ExecStart=/usr/sbin/snmpd -LOw -u Debian-snmp -g Debian-snmp -I -system_mib,smux,mteTrigger,mteTriggerConf -f -p /run/snmpd.pid
ExecReload=/bin/kill -HUP $MAINPID

[Install]
WantedBy=multi-user.target

To see the status of the service:

systemctl status snmpd.service
journalctl -u snmpd.service -f

To restart the service after modification:

sudo systemctl daemon-reload
sudo systemctl restart snmpd.service

The command line arguments -u and -g are for the user id and group id of the snmpd process will use after its initial startup. They are not necessary to use snmpd. However snmpd must be started with permissions to open relevant sockets, typically root permissions.

If you use “system V init” instead of systemd, then snmpd is typically started by a script file named /etc/init.d/snmpd. Change the snmpd command line arguments in the file, typically via SNMPDOPTS. Stop and start the service with:

sudo /etc/init.d/snmpd stop
sudo /etc/init.d/snmpd start

Configuration file for snmpd

The file snmpd.conf controls access to the snmp agent. It should be set to listen on all interfaces and allow read-write access to the Profinet MIB:s. On Ubuntu Linux you should change /etc/snmp/snmpd.conf to read:

master  agentx
agentaddress  udp:161
view   systemonly  included   .1.3.6.1.2.1.1
view   systemonly  included   .1.3.6.1.2.1.2.2
view   systemonly  included   .1.0.8802.1.1.2
rocommunity  public  default -V systemonly
rwcommunity  private default -V systemonly

If your Linux distribution does give a long description for ifDesc you can override it by adding a line to the snmpd.conf file. Adapt the interface index (last digit in OID) and the interface name:

override 1.3.6.1.2.1.2.2.1.2.3 octet_str "enp0s31f6"

See Network topology detection for more details on SNMP and how to verify the SNMP communication to the p-net stack.

Start your application after snmpd

You probably would like your application to wait for the snmpd application to be up and running. If you use systemd as init system, modify this line in the [Unit] part of your .service file:

After=network.target snmpd.service

You might also need to add this to the [Service] part of your .service file:

ExecStartPre=/usr/bin/sleep 0.3

If the p-net application fails to connect to snmpd, a message “Warning: Failed to connect to the agentx master agent” will be written to the p-net sample app log file every 15 seconds.

Debugging snmpd settings

The command line argument -LOw for snmpd sets the snmpd logging to standard out with log level “warning”. To change to log level debug, use -LOd. You should also use the -D flag to select which debug messages you are interested in. Use the -Dagentx command line argument to debug the agentx communication between the snmpd and the subagent in the p-net stack. A log example when asked for a single OID:

Connection from UDP: [192.168.0.30]:43833->[192.168.0.50]:161
agentx/master: agentx master handler starting, mode = 0xa0
agentx/master: request for variable (iso.3.6.1.2.1.1.4.0)
agentx/master: sending pdu (req=0x8,trans=0x7,sess=0x6)
agentx_build: packet built okay
agentx/master: got response errstat=0, (req=0x8,trans=0x7,sess=0x6)
agentx/master: agentx_got_response() beginning...
agentx/master:   handle_agentx_response: processing: iso.3.6.1.2.1.1.4.0
agentx/master: handle_agentx_response() finishing...

Note that there might be a warning message “pcilib: Cannot open /proc/bus/pci” in the snmpd log if you specify that it should use all interfaces. That is because it will look also for (possibly non-existing) PCI interfaces.

To trouble-shoot snmpd issues, verify that no other snmpd instances are running:

ps -ef | grep snmpd

and verify that no other process is using UDP port 161:

sudo lsof -i udp -n -P

snmpd in a Yocto build

In an embedded Linux Yocto build, you would include the snmpd daemon by using the net-snmp recipe.

Persistent logs

To make the journalctl logs persistent between restarts:

sudo mkdir -p /var/log/journal
sudo systemd-tmpfiles --create --prefix /var/log/journal

Remove all contents of the journalctl logs:

sudo journalctl --rotate
sudo journalctl --vacuum-time=1s

The configurations for journalctl are located in /etc/systemd/journald.conf. If you do experiments with frequent reboots, it might be useful to change some values:

SyncIntervalSec=10s
MaxRetentionSec=4h

Boot time optimization

The boot time should be less than approximately 15 seconds, for the “missing peer” alarm to be sent within 30 s after the power on.

To improve the startup time of your Linux device, it is useful to study what is delaying the start. If you use the “systemd” init system, you can use these commands to analyze the startup:

systemd-analyze
systemd-analyze blame
systemd-analyze critical-chain pnet-sampleapp.service

To decrease the startup time, disable services you don’t use. On a Raspberry Pi it might be for example:

sudo systemctl disable triggerhappy triggerhappy.socket apt-daily.timer apt-daily-upgrade.timer logrotate.timer  rpi-display-backlight lightdm bluetooth hciuart rsync cups cups-browsed alsa-state avahi-daemon

Other applications that you might disable for experimentation:

sudo systemctl disable snapd snapd.socket wpa_supplicant systemd-timesyncd dhcpcd

Debug the sample application on a Linux Laptop

It can be convenient to be able to run the sample application and the p-net stack in a debugger tool. It is easy using gdb and the Visual Studio Code editor.

First make sure you can run the application from a terminal on your Linux laptop.

Next step is to be able to run it from the terminal within Visual Studio Code. In case of compilation error messages, you can click on the code line given in the terminal (within Visual Studio Code) and the corresponding file will be opened.

To use debug features while running (for example breakpoints) you need to adapt the settings file for Visual Studio Code. Click the “Run and Debug” icon in the left side tool bar. Then click “Create a launch.json file”. In the “Select environment”, use “C++ (GDB/LLDB)”.

Modify the launch.json file to point at the correct executable, working directory and to use correct command line arguments.

If you need to run the application with root permissions, you need to add a path in the "miDebuggerPath" field. It should point to a text file typically named gdb, with this content:

pkexec /usr/bin/gdb "$@"

Put the gdb file for example in the .vscode subdirectory within the p-net directory. Set the executable flag:

chmod +x gdb

An example of a launch.json file:

{
   "version": "0.2.0",
   "configurations": [

      {
         "name": "(gdb) Launch",
         "type": "cppdbg",
         "request": "launch",
         "program": "${workspaceFolder}/build/pn_dev",
         "args": ["-vv", "-i", "enp0s31f6"],
         "stopAtEntry": false,
         "cwd": "${workspaceFolder}/build/",
         "environment": [],
         "externalConsole": false,
         "MIMode": "gdb",
         "miDebuggerPath": "${workspaceFolder}/.vscode/gdb",
         "setupCommands": [
            {
               "description": "Enable pretty-printing for gdb",
               "text": "-enable-pretty-printing",
               "ignoreFailures": true
            }
         ]
      }

   ]
}

The given "args" command line arguments in the example is for increasing the verbosity level and to set the Ethernet interface name. Adapt those and also paths to your particular setup.

Use the CMAKE_BUILD_TYPE setting as Debug when running the executable via the debugger.

Start the debugging by clicking on the small green “Run” icon on the “Run and Debug” page. It will stop at any breakpoint. Set a breakpoint in any file by clicking on a line to the left of the line number.