Install Arch Linux on EFI

Most what you will find in this post comes from this gist. I’m rewritting this here as a note in any case. Some more info about the installation process here on ArchWiki and also more info about the post-installation process.

  1. Boot USB flash drive and make sure it’s connected via Ethernet.
  2. Change terminal keys if you are not in qwerty:
    loadkeys fr
  3. Disable the beeping sound (this one will save your ears and sanity):
    setterm -blength 0
  4. Check if the system was booted with UEFI:
    cat /sys/firmware/efi/fw_platform_size

    It should exists and be 64 if it’s booted in UEFI x86_64. If that’s the case, continue.

  5. Check that you have an IP address and try a ping to check your Internet connectivity:
    ip address
    ping 8.8.8.8
    
  6. Update system clock and check status:
    timedatectl set-ntp true
    timedatectl status
  7. Enable SSH, this might be useful if you want to continue the installation from elsewhere or transfer files via sftp:
    systemctl start sshd
  8. List the disks then proceed with creating the partitions:
    fdisk -l
    cfdisk /dev/sda
    

    Create a EFI partition of 256M to 512M, a several GB swap partition and what is left with a Linux root partition.

  9. Format the partitions:
    mkfs.fat -F32 /dev/sda1
    mkfs.ext4 -L root -m 0 /dev/sda3
    
  10. Mount the root partition:
    mount -o noatime /dev/sda3 /mnt
    
  11. Install the base packages:
    pacstrap -Ki /mnt base linux linux-firmware
    
  12. Generate the fstab:
    genfstab -U -p /mnt >> /mnt/etc/fstab
    
  13. Chroot in the filesystem:
    arch-chroot /mnt
    
  14. Configure the terminal keyboard:
    vim /etc/vconsole.conf
  15. Set the timezone:
    ln -sf /usr/share/zoneinfo/Europe/Brussels /etc/localtime
    
  16. Update the hardware clock:
    hwclock --systohc
    
  17. Install other packages:
    pacman -S grub efibootmgr dosfstools openssh os-prober mtools net-tools inetutils netctl dhcpcd dhclient vim
    
  18. Edit and set-up the locale:
    vim /etc/locale.gen
    locale-gen
    
  19. Setup root password:
    passwd
    
  20. Create and mount EFI directory:
    mkdir /boot/EFI
    mount -o noatime /dev/sda1 /boot/EFI
  21. Time to install the GRUB bootloader and write the config:
    grub-install --target=x86_64-efi --bootloader-id=grub_uefi --recheck
    grub-mkconfig -o /boot/grub/grub.cfg
    
  22. If needed you might configure an extra entry within the GRUB boot list, for instance for a dualboot with FreeBSD. To that end, edit /etc/grub.d/40_custom and add (at the end of this file):
    menuentry FreeBSD {
      insmod ufs2
      set root='(hd0,gpt3)'
      chainloader /boot/loader.efi
    }
    

    Then update the grub configuration with:

    grub-mkconfig -o /boot/grub/grub.cfg
  23. Time to reboot:
    exit
    reboot
    

Charade 💥

We’ll meet againDon’t know whereDon’t know whenBut I know we’ll meet again some sunny day
Keep smiling throughJust like you always do‘Til the blue skies drive the dark clouds far away

So will you please say helloTo the folks that I knowTell them I won’t be longThey’ll be happy to knowThat as you saw me goI was singing this song

We’ll meet againDon’t know whereDon’t know whenBut I know we’ll meet again some sunny day

InfluxDB and collectd time mismatch

Recently I’ve been playing a bit with Grafana and InfluxDB data sources populated by collectd for the most part. However when trying to explore the data in InfluxDB, all times were in 1970-01-01. The epoch is often used as a kind of null value in InfluxDB. However in this case, the time value were increasing. The problem was that there was a mismatch between the timestamp sent by collectd and the way InfluxDB was trying to parse them.

Collectd used the write_influxdb_udp write plugin which apparently sends timestamp in milliseconds, but the [[udp]] listener of InfluxDB was probably expecting them to be in nanoseconds. Hence, there factor 1000000 between the two timestamp formats. You can control which format InfluxDB expects on its [[udp]] listener using the following parameter:

# InfluxDB precision for timestamps on received points ("" or "n", "u", "ms", "s", "m", "h")
precision = "ms"

Port configure fails on ARM64

On FreeBSD, if you are trying to build a port but it fails at the configure step with a message similar to this:

checking build system type... Invalid configuration `arm64-portbld-freebsd13.2': machine `arm64-portbld' not recognized
configure: error: /bin/sh ./build-aux/config.sub arm64-portbld-freebsd13.2 failed

Here’s a quick-fix that might work for you:

export CONFIGURE_TARGET=arm64-unknown-freebsd13.2
make install

This is similar to passing --host arm64-unknown-freebsd13.2 to the configure script instead of trying to guess it.

Post install ArchLinux

In the past few months, I had to install ArchLinux several times. While it’s now my Linux distribution of choice for an everyday use, a clean install of Arch is rather bland. So in this post, I’ll try to resume the different step I took to spice a default Arch install a bit more to my taste. Most of the choices here are purely personals.

New user

By default, no user is created, so you have to create one along with its home directory. Also ensure that your home is in 750 instead of 755.

useradd -m youruser
chmod 750 /home/youruser

Fstab and tmpfs

By default, on a new install, /etc/fstab comes up mostly empty as most of it is hidden away by systemd. But I usually change some options and add tmpfs. Here’s an example:

/dev/vda2 / ext4 rw,noatime,nodiscard,stripe=4 0 1
/dev/vda1 /boot vfat rw,noatime,fmask=0022,dmask=0022,codepage=437,iocharset=ascii,shortname=mixed,utf8,errors=remount-ro	0 2

/dev/vdb1 none swap sw 0 0
/dev/vdb2 /mnt/data ext4 rw,noatime,nodiscard 0 0

tmpfs /tmp tmpfs noatime,mode=1777 0 0
tmpfs /run tmpfs noatime,nosuid,noexec,mode=755 0 0
tmpfs /run/shm tmpfs noatime,nosuid,nodev,mode=1777 0 0

pacman cache

If you have a separate data partition/hdd, it may be a good idea to move the pacman cache there. However you cannot do so using symlinks, pacman won’t like that at all. Instead you have to edit the CacheDir entry in /etc/pacman.conf.

yay

Arch comes with its binary package manager (pacman) and also the community maintained Arch User Repository (AUR) providing access to more packages that are generally built from source. Yay is a AUR package manager so you don’t have to clone and install AUR repos manually.

Note that the commands below need to be run as your normal user, otherwise makepkg will complain about possible catastrophic happenstances.

sudo pacman -S --needed base-devel git
git clone https://aur.archlinux.org/yay.git
cd yay
makepkg -si

legacy network interface name

Back in the days, network interfaces on Linux had simple names like eth0, wlan0, and so on. This changed multiple times because the order in which the interface drivers are loaded make these names not 100% predictable. However, if you know that your boot order is pretty static and never change, you might want to get the legacy naming scheme. To do so, either add net.ifnames=0 to the kernel parameters or override the appropriate udev rule. In this case I use the latter option.

ln -s /dev/null /etc/udev/rules.d/80-net-setup-link.rules

netctl

I prefer to use netctl instead of systemd-networkd to manage the network. Since I constantly use other Unix and Unix-likes systems that are not Linux, and since I’ve been doing so for decades, I also prefer to use ifconfig instead of ip. When asked I also choose openresolv instead of systemd-resolved, the latter tries to do too many things in your back.

pacman -S net-tools inetutils netctl dhcpcd dhclient
systemctl enable netctl

Then you have to create a default profile, for instance in /etc/netctl/network. Here is a default config that configures the interface with DHCP for IPv4 and SLAAC for IPv6:

Description="Basic DHCP ethernet connection"
Interface=eth0
Connection=ethernet
IP=dhcp
IP6=stateless

You still have to enable the profile:

netctl enable network

Some packages

Here is the bare minimum I would install on a new install, whether headless or xorg powered.

  • uptimed
  • ntp/chrony
  • ncdu
  • zsh
  • htop
  • starship
  • neovim
  • wget/curl/lynx
  • tcpdump/nmap
  • fzf
  • tree
  • bzip2/xz/gzip/zstd
  • the_silver_searcher
  • git
  • cpio
  • rsync
  • dialog
  • ipv6calc
  • dos2unix
  • exa/bat

Some extra packages

  • openssh: remote access/sync stuff and so on
  • bindfs: useful if you need to rebind user/permission on mount points, for instance on a shared mount
  • tldr: recall any command usage (I recommend the tealdeer client, written in Rust)
  • doggo: DNS queries
  • vulkan-virtio/mesa-vdpau: useful for graphical acceleration in a Qemu VM

Devd doesn’t trigger LINK_UP

On FreeBSD, you can use devd to trigger scripts that react to device state changes. For instance, you plug/remove a device, or you connect/disconnect an Ethernet cable.

I had to use this kind of rule to restart a service when an interface is reconnected. However the rule would not trigger when the cable was reconnected.

The reason was that default rules in /etc/devd.conf were failing, hence stopping the execution of the next rules. In particular service dhclient quietstart $subsystem".

The solution was either to comment these lines in devd.conf or give my custom devd configuration a higher priority.

Override rc order in FreeBSD

In FreeBSD as in most other Operating Systems, the boot process consist of starting a set of scripts/services/daemons/processes. Each of those has constraints like depending-on or starting before other scripts for instance.

On a default FreeBSD install, this order would be determined by the packages you install, each of them installing a script in /usr/local/etc/rc.d that specifies its constraints requirements.

What, however, if you wanted to change the order of the boot process? For instance, you have a script that by default starts just after the network is ready, but in your case, it specifically has to start after another script for everything to work properly.

Well, I was confronted to that particular problem, and the answer is cross-dependency-scripts or whatever you want to call them.
Suppose that you have the following scripts in your boot process: A, B, C, D. By default, B, C and D start just after A. But you want to change that so B starts after D and C starts after B.

If you changed the order dependency in script B and C directly, that change would be overwritten on the next package update. Instead we add two empty scripts __B and __C that will just enforce the dependence. That is, __B starts after D and before B, __C starts after B and before C.

Looking at the code, at the beginning of the original scripts you would find:

-- rc.d/A
#!/bin/sh

# PROVIDE: A
-- rc.d/B
#!/bin/sh

# PROVIDE: B
# REQUIRE: A
-- rc.d/C
#!/bin/sh

# PROVIDE: C
# REQUIRE: A
-- rc.d/D
#!/bin/sh

# PROVIDE: D
# REQUIRE: A

Thus you would add two scripts __B and __D that contains:

-- rc.d/__B
#!/bin/sh

# PROVIDE: __B
# REQUIRE: D
# BEFORE: B
-- rc.d/__C
#!/bin/sh

# PROVIDE: __C
# REQUIRE: B
# BEFORE: C

FreeBSD on NanoPi R2S

The NanoPi R2S is a nice little ARM board that can serve nicely as a home router or firewall. It is comparable in power to a RaspberrryPi 3 with a 4 cores ARM Cortex-A53 SoC, namely the Rockchip RK3328. It has no video or sound output, only a handful GPIOs compared to a RPi, but it has one great advantage. It has 2 Ethernet ports, one of them is a true Gigabit internal card and the second is also a Gigabit connected through the internal USB3, so it’s a bit slower. On the RPi3, if you want 2 Gigabit Ethernet ports, you need an external card and both ports would run on the USB3, drastically limiting the bandwidth.

They generally come with a heatsink and a fan integrated as the board is quite small compared to a RPi and heats up more easily. People generally use this board with OpenWrt or Ubuntu. In the past, I also used it with Armbian as my home network gateway. People also managed to run it on OpenBSD. But this post focuses on FreeBSD.

ARM64 has been a tier-1 architecture on FreeBSD for more than a year now, which I discussed in this post. I managed to run the RPi 2B+, 3 and 4 easily, but my attempts with the Nanopi R2S proved rather unsuccessful and had their fair share of kernel panics.

Fast forward one year, and we are now at FreeBSD 13.1-p1. So I recently gave it another try, and not only is the whole experience much more stable, the installing process is also much easier and straightforward.

Installation

To install FreeBSD, I used the image provided at PersonalBSD. It’s a custom image based on a patched version of FreeBSD 13. It’s quite customized in fact, and point to its own repo by default. It starts sshd by default, and run both interfaces on DHCP. It has pubkey root login enabled and also has another admin user installed.

The rc.conf has growfs enabled, so the first boot will grow the ROOT UFS partition to the size of your SD card. It’s all GPT. There is a 256MB swap partition, but you can add a file based swap if you want. For instance in /etc/fstab:

md99 none swap sw,file=/.swap,late 0 0

The root partition has the following options enabled:

tunefs: POSIX.1e ACLs: (-a)                                disabled
tunefs: NFSv4 ACLs: (-N)                                   disabled
tunefs: MAC multilabel: (-l)                               disabled
tunefs: soft updates: (-n)                                 disabled
tunefs: soft update journaling: (-j)                       disabled
tunefs: gjournal: (-J)                                     disabled
tunefs: trim: (-t)                                         disabled
tunefs: maximum blocks per file in a cylinder group: (-e)  4096
tunefs: average file size: (-f)                            16384
tunefs: average number of files in a directory: (-s)       64
tunefs: minimum percentage of free space: (-m)             8%
tunefs: space to hold for metadata blocks: (-k)            2768
tunefs: optimization preference: (-o)                      space

It has soft updates disabled, which means that if the board has a hard reboot, you are in for some fsck nightmare. You can enable softupdates offline when the card is connected to your computer (running FreeBSD) for instance:

tunefs -n /dev/da0p2

I highly recommend to enable soft updates to save you much hassle.

Playing around

By default there is no EEPROM for the MAC addresses so they are randomly generated on each boot. Keep this in mind if you want to use IPv6 and SLAAC. There is also three status LEDs on the board. You can control them from the command line with echo 0|1 > /dev/led/nanopi-r2s:*. The custom image comes with a daemon and rc.local shell lines to setup a default state for the LEDs, but you can easily disable it.

The two interfaces are dwc0 for the Rockchip internal card, and ue0 for the card connected through USB3. Here is a quick test with iperf3 using UDP on both interfaces. Results are given in Mbits/sec.

TX RX
dwc0 765 946
ue0 784 370

 

Running it

But does it fit an use for a full fledged Internet gateway? I ran the Nanopi R2S for some time now as a home network gateway, and while it worked very well most of the time, the R2S would from time to time become completely inaccessible. Although it did not seem to panic as scripts where still running behind the scene. I could not identify what the problem was, but I know that the problem happened when either the Ethernet cable on the LAN interface was disconnected, or when too much traffic arrived on the Ethernet port.

AMD Renoir GPU on FreeBSD 13 (bis)

In a previous post, I explained that I backported the 5.5-stable branch of drm-kmod and got it running on FreeBSD 13.0-RELEASE although some bugs persisted.

Since then I’ve received several requests if it was possible to access the code or if a port was available. However the answer was always that it was a quick and dirty patch, panic do occur and that it wasn’t published on purpose (but a tarball was available).

But I’ve been at it again. I first tried to backport the 5.7-stable branch to FreeBSD 13. It did compile and display worked. But there were several bugs that I was unable to fix.

So I restarted the patch over 5.5-stable but this time dedicated more than 10 minutes for the task. The thing works and even fixed a bug in the process. Also it does now compile on a fresh FreeBSD 13.0-RELEASE ✌️

This new version is available on my github as 5.5-fbsd13release branch. Feel free to clone and try. Intel i915 is still not supported but could be if someone is interested and willing to try it.

Still no port tho, as I’m not confident at all in my understanding of drm-kmod and ability to contribute.