Network initialization using libBSD

I was going through the libBSD example and the quick start guide to initialize a simple networking example (Chapter 7. Sockets | FreeBSD Documentation Portal - connect to a NIST server to get the current time). When calling connect I am getting the error “network is unreachable”. I am pretty sure I am missing correctly initializing the network and the bridging between my Linux computer and qemu may (probably is) also be incorrect (using arm/xilinx_zynq_a9_qemu BSP), however I have tried a variety of different configurations and headers following different examples and still haven’t gotten the configuration to work. I was thinking I needed to create an /etc/rc.conf, however I don’t think I have put the correct information into it. Any guidance anyone has on how to do the initialization and qemu TAP connection to the internet would be amazing here!! Thanks in advance for the help!! Let me know if there is any other info I can/should provide (I didn’t include my Init function because it is currently a mess of different attempts from the examples I could find, but can provide it if it will be helpful).

Welcome to RTEMS

What is your qemu command line? Qemu has a lot of ways to run networking.

What is the console output?

Thanks
Chris

Thanks and thank you so much for getting back to me!! Here is everything that I am running post ./waf

krocha@system76-mini-00:~/Documents/rtems_sockets/app/networking$ sudo ip tuntap add qtap mode tap user $(whoami)
sudo ip link set dev qtap up
sudo ip addr add 169.254.1.1/16 dev qtap
[sudo] password for krocha: 
krocha@system76-mini-00:~/Documents/rtems_sockets/app/networking$ qemu-system-arm -no-reboot -serial null -serial mon:stdio -nographic   -M xilinx-zynq-a9 -m 256M -net nic,model=cadence_gem  -netdev tap,id=net0,ifname=qtap,script=no,downscript=no  -kernel build/arm-rtems7-xilinx_zynq_a9_qemu/hello.exe
qemu-system-arm: warning: hub 0 is not connected to host network
qemu-system-arm: warning: netdev net0 has no peer
qemu-system-arm: warning: nic cadence_gem.1 has no peer
nexus0: <RTEMS Nexus device>
cgem0: <Cadence CGEM Gigabit Ethernet Interface> on nexus0
miibus0: <MII bus> on cgem0
e1000phy0: <Marvell 88E1111 Gigabit PHY> PHY 7 on miibus0
e1000phy0:  none, 10baseT, 10baseT-FDX, 100baseTX, 100baseTX-FDX, 1000baseT-FDX, 1000baseT-FDX-master, auto
info: cgem0: Ethernet address: 52:54:00:12:34:56
arasan_sdhci1: <Arasan SDIO> on nexus0
arasan_sdhci1-slot0: Hardware doesn't specify base clock frequency, using 50MHz as default.
arasan_sdhci1-slot0: Hardware doesn't specify timeout clock frequency, setting BROKEN_TIMEOUT quirk.
arasan_sdhci0: <Arasan SDIO> on nexus0
arasan_sdhci0-slot0: Hardware doesn't specify base clock frequency, using 50MHz as default.
arasan_sdhci0-slot0: Hardware doesn't specify timeout clock frequency, setting BROKEN_TIMEOUT quirk.
zy7_slcr0: <Zynq-7000 slcr block> on nexus0
rc.conf: loading: /etc/rc.conf
rc.conf: start: /etc/rc.conf size:142, timeout: 30
rc.conf: running
Setting hostname: rtems7-libbsd.
Starting network:  lo0 rc.conf: /etc/rc.conf: ifconfig: ifconfig lo0 inet 127.0.0.1 netmask 255.0.0.0 up
cgem0 rc.conf: /etc/rc.conf: ifconfig: ifconfig cgem0 inet 169.254.1.1 netmask 255.255.0.0 up
rc.conf: /etc/rc.conf: ifconfig: ifconfig cgem0 ether c2:7e:a3:e0:bf:a5 alias
.
 cgem0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500
        options=80008<VLAN_MTU,LINKSTATE>
        ether c2:7e:a3:e0:bf:a5
        hwaddr 52:54:00:12:34:56
        inet 169.254.1.1 netmask 0xffff0000 broadcast 169.254.255.255
        nd6 options=29<PERFORMNUD,IFDISABLED,AUTO_LINKLOCAL>
        media: Ethernet autoselect (100baseTX <full-duplex>)
        status: active
lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> metric 0 mtu 16384
        options=680003<RXCSUM,TXCSUM,LINKSTATE,RXCSUM_IPV6,TXCSUM_IPV6>
        inet6 ::1 prefixlen 128
        inet6 fe80::1%lo0 prefixlen 64 scopeid 0x2
        inet 127.0.0.1 netmask 0xff000000
        nd6 options=21<PERFORMNUD,AUTO_LINKLOCAL>
        groups: lo
rc.conf: services done
rc.conf: finished
connect: Network is unreachable

*** EXIT STATUS NOT ZERO ***
exit source: 5 (RTEMS_FATAL_SOURCE_EXIT)
exit code: 2 (0x00000002)
RTEMS version: 7.0.0.3d1db73ef0de7cc396183f6c599a301f355d2bba
RTEMS tools: 13.4.0 20250605 (RTEMS 7, RSB 3d1db73ef0de7cc396183f6c599a301f355d2bba, Newlib 038afec1)
executing thread ID: 0x0a010001
executing thread name: UI1 

If it is easiest/helpful, I can put my source code (the init.cpp and networking.cpp) up on rtems git or on my github so you can see it or paste it here.

What is in /etc./rc.conf?

Oh, sorry I see you used verbose :slight_smile:

Are you able to drop into the RTEMS shell rather than exit then your test code after it fails?

In the shell you can run ifconfig, netstat and ping and these can help when testing.

I am sorry but I am not a Linux user and I have no idea about these taps. I use VDE with a single tap on FreeBSD and sort of side step a number of issues.

I have not figured out how to drop into the RTEMS shell, however I can try and figure that out. If you have a recommended guide for that, that would be really helpful. Here is what I was doing networking wise in my C++ file to init the rc config and networking (I got it from an example, but don’t remember where from and tried to edit it from there). Are you running FreeBSD as your os?

static const char* rc_conf =
  "# /etc/rc.conf\n" \
  "hostname=\"rtems7-libbsd\"\n" \
  "ifconfig_cgem0=\"inet 169.254.1.1 netmask 255.255.0.0\"\n" \
  "ifconfig_cgem0_alias0=\"ether c2:7e:a3:e0:bf:a5\"\n";
  //"defaultrouter=\"192.168.4.1\"\n"; 
  //"telnetd_enable=\"YES\"\n";

void start_network(void)
{
  FILE *rc;
  int   r;

  /*
   * Initialise libbsd.
   */
  rtems_bsd_initialize();

  /*
   * Create the /etc/rc,conf, assume /etc exists.
   */
  rc = fopen("/etc/rc.conf", "w");
  if (rc_conf == NULL) {
    printf("error: cannot create /etc/rc.conf\n");
    exit(1);
  }

  fprintf(rc, rc_conf);
  fclose(rc);

  /*
   * Arguments are timeout and trace
   */
  r = rtems_bsd_run_etc_rc_conf(30, true);
  if (r < 0) {
    printf("error: loading /etc/rc.conf failed: %s\n",strerror(errno));
    exit(1);
  }
}

Does this DEFAULT_NETWORK_SHELL piece of code help?

I use for DHCP:

 std::ofstream rc_conf("/etc/rc.conf");
 rc_conf << "hostname=\"" << hostname << "\"" << std::endl;
 rc_conf << "dhcpcd_priority=\"200\"" << std::endl;
 rc_conf << "dhcpcd_options=\"--debug --nobackground --timeout 30\"" << std::endl;
 rc_conf.close();

and I have:

void init() {
    rtems_bsd_initialize();
    rtems_shell_add_cmd_struct(&bsp_interrupt_shell_command);
    rtems_shell_add_cmd_struct(&rtems_shell_ARP_Command);
    rtems_shell_add_cmd_struct(&rtems_shell_HOSTNAME_Command);
    rtems_shell_add_cmd_struct(&rtems_shell_IFCONFIG_Command);
    rtems_shell_add_cmd_struct(&rtems_shell_NETSTAT_Command);
    rtems_shell_add_cmd_struct(&rtems_shell_PING_Command);
    rtems_shell_add_cmd_struct(&rtems_shell_ROUTE_Command);
    rtems_shell_add_cmd_struct(&rtems_shell_SYSCTL_Command);
    rtems_shell_add_cmd_struct(&rtems_shell_TCPDUMP_Command);
}

And for rc.conf:

void run_rc_conf(int timeout, bool trace) {
    int r = rtems_bsd_run_etc_rc_conf(timeout, trace);
    if (r < 0) {
        std::cout << "network: Failed to initialize" << std::endl;
    }
}

The other needed bit is the configuration:

/*
 * Configure LibBSD.
 */
#include <bsp/irq.h>

#define RTEMS_BSD_CONFIG_BSP_CONFIG

#define RTEMS_BSD_CONFIG_NET_PF_UNIX
#define RTEMS_BSD_CONFIG_NET_IF_BRIDGE
#define RTEMS_BSD_CONFIG_NET_IF_LAGG
#define RTEMS_BSD_CONFIG_NET_IF_VLAN

#define RTEMS_BSD_CONFIG_DOMAIN_PAGE_MBUFS_SIZE (128 * 1024 * 1024)

#define RTEMS_BSD_CONFIG_INIT

#include <bsp/irq-info.h>
#include <rtems/netcmds-config.h>
#include <machine/rtems-bsd-config.h>

#include <rtems/shell.h>
#include <rtems/telnetd.h>

One thing to watch for is waiting for the link up to happen. The PHY devices on boards have PLLs which need to resync to the ethernet signals. After starting LibBSD and then running rc.conf wait for the interface to initialise and get itself sorted. This will be happening concurrently to your thread. The code is:

static void
default_wait_for_link_up( const char *name )
{
	size_t seconds = 0;
	while ( true ) {
		bool link_active = false;
		assert(rtems_bsd_iface_link_state( name, &link_active ) == 0);
		if (link_active) {
			return;
		}
		sleep( 1 );
		++seconds;
		if (seconds > 10) {
			printf("error: %s: no active link\n", name);
			assert(seconds < 10);
		}
	}
}

It calls rtems_bsd_iface_link_state() and that can be found under rtemsbsd.

Yes FreeBSD on my development machines. Mac as a terminal. I have used this set up for over 25 years.

1 Like

Think I am close to having all of that in my implementation. A few of the things I am missing are what goes in the name input for default_wait_for_link_up and what is the header for the init function rtems_shell_add_cmd_struct inputs?

Thank you again so so much for all your help.

The wait takes the name of the interface to monitor and waits until it is up.

1 Like

Thank you for all the help and sorry for all the probably basic questions. For the rtems_bsd_iface_link_state include, I have #include <rtems/bsd/iface.h> which looked like it could be the correct header, but I am still getting undefined reference. Is there any chance you would know if I am missing the correct header or have libBSD misconfigured in some way?

If you are making the call from C++ try adding:

extern "C" {}

around the header include. It could be the signature you have is C++ and not C.

If this fixes the problem could you please raise an issue for libbsd about this as it is a bug.

Thanks!! That fixed compilation and I just made an issue for it (C++ undefined reference when using rtems/bsd/iface.h functions (#57) · Issues · RTEMS / Packages / LibBSD · GitLab).

I am currently getting an error with the wait for link up. How do I turn on verbosity on the rtems side of libBSD? These options --freebsd-options=bootverbose,verbose_sysinit,bus_debug,debug_locks,ktr,ktr_verbose feel like they are a layer too low, but I may be wrong here.

I pulled the interface name using if_indextoname(1, &ifnamebuf[0]).

assertion "rtems_bsd_iface_link_state( name, &link_active ) == 0" failed: file "../../networking.cpp", line 52, function: void default_wait_for_link_up(const char*)

*** FATAL ***

The interface name for the Zynq is cgem0 by default. Are you using that?

Those options are for development and are kernel level options and need a more detailed kernel knowledge.

I again suggest getting the shell running. Once running the ifconfig command will list the interfaces and also a lot of state information. You can also manually do a range of things such as run ping and watch with Wireshark the ARP request.

Yea, think so. I also added the code for the console running, but it just runs past the console init. It looked like it spawns off a new task however when I hit the end of init the program ends. I tried throwing an infinite loop at the bottom of my init as some internet examples did, but then obviously the console just hung.

RTEMS Shell on /dev/console. Use 'help' to list commands.
SHLL [/] # arasan_sdhci1: <Arasan SDIO> on nexus0
arasan_sdhci1-slot0: Hardware doesn't specify base clock frequency, using 50MHz as default.

Check for a wait option when starting the shell. It should wait until it completes.

1 Like

Also start it once the network wait completes.

1 Like