IPXE and Coreboot Ramblings

This is more a collection of notes compiled from my command history. It hasn’t been repeated…

I have a motherboard that is Coreboot compatible. Coreboot comes with a basic payload that permits booting from local disks, but requires other payloads to be added if required – such as IPXE.

Need some info first, such as the NIC PCI ID

root@blackbird:~# lspci  | grep -i net
00:0a.0 Bridge: NVIDIA Corporation CK804 Ethernet Controller (rev a3)
root@blackbird:~# lspci -s 00:0a.0 -nnn
00:0a.0 Bridge [0680]: NVIDIA Corporation CK804 Ethernet Controller [10de:0057] (rev a3)

Get, configure and build IPXE.

git clone git://git.ipxe.org/ipxe.git
cd ipxe/src/

Insert this into config/local/general.h – it defines what gets included into the ROM image, such as menu support, iscsi support, etc

#undef PXE_STACK               /* PXE stack in iPXE – you want this! */
#undef PXE_MENU                /* PXE menu booting */
#undef DOWNLOAD_PROTO_TFTP     /* Trivial File Transfer Protocol */
#undef SANBOOT_PROTO_ISCSI     /* iSCSI protocol */
#undef SANBOOT_PROTO_AOE       /* AoE protocol */
#undef SANBOOT_PROTO_IB_SRP    /* Infiniband SCSI RDMA protocol */
#undef SANBOOT_PROTO_FCP       /* Fibre Channel protocol */
#undef CRYPTO_80211_WEP        /* WEP encryption (deprecated and insecure!) */
#undef CRYPTO_80211_WPA        /* WPA Personal, authenticating with passphrase */
#undef CRYPTO_80211_WPA2       /* Add support for stronger WPA cryptography */
#undef IMAGE_NBI               /* NBI image support */
#undef IMAGE_ELF               /* ELF image support */
#undef IMAGE_MULTIBOOT         /* MultiBoot image support */
#undef IMAGE_PXE               /* PXE image support */
#define        IMAGE_SCRIPT            /* iPXE script image support */
#define        IMAGE_BZIMAGE           /* Linux bzImage image support */
#undef IMAGE_COMBOOT           /* SYSLINUX COMBOOT image support */
#undef IMAGE_EFI               /* EFI image support */
#undef IMAGE_SDI               /* SDI image support */
#undef NVO_CMD                 /* Non-volatile option storage commands */
#define CONFIG_CMD              /* Option configuration console */
#undef FCMGMT_CMD              /* Fibre Channel management commands */
#undef ROUTE_CMD               /* Routing table management commands */
#define IMAGE_CMD               /* Image management commands */
#define SANBOOT_CMD             /* SAN boot commands */
#define MENU_CMD                /* Menu commands */
#undef LOGIN_CMD               /* Login command */
#undef SYNC_CMD                /* Sync command */
#undef NSLOOKUP_CMD            /* DNS resolving command */
#undef TIME_CMD                /* Time commands */
#undef DIGEST_CMD              /* Image crypto digest commands */
#undef LOTEST_CMD              /* Loopback testing commands */
#undef VLAN_CMD                /* VLAN commands */
#undef PXE_CMD         /* PXE commands */
#undef REBOOT_CMD             /* Reboot command */
#undef IMAGE_TRUST_CMD /* Image trust management commands */

And the command that will be run at startup of ipxe should be inserted into shell.ipxe



chain –autofree http://core.vpn.glasgownet.com/menu.ipxe

Take the PCI ID, concatenate it as the ROM filename, and embed the script.

make -j3 bin/10de0057.rom EMBED=./shell.ipxe

Now the IPXE payload is ready.


For Coreboot,

git clone https://review.coreboot.org/coreboot
cd coreboot
git submodule update –init –checkout
make nconfig

In nconfig, select the appropriate board.

Save, exit.

Build the cross compilers

make crossgcc CPUS=4

Build the firmware


The coreboot firmware is saved as build/coreboot.rom, but needs the payload added.

./build/cbfstool ./build/coreboot.rom add -f ../ipxe/src/bin/10de0057.rom -n pci10de,0057.rom -t raw
./build/cbfstool ./build/coreboot.rom print

To remove the payload, in the event of wanting to add a new version

./build/cbfstool ./build/coreboot.rom remove -n pci10de,0057.rom

The coreboot.rom file is now ready to be copied to the target machine and flashed.

If a backup is required, use

flashrom -p internal -r backup.bin

To flash,

flashrom -p internal -w coreboot.rom

AWS G2 GPU vs unattended-upgrade

Recently we noticed that our AWS G2 GPU instances were no longer working correctly after a reboot. We were being greeted with the joyful message of

[ 6710.061115] NVRM: The NVIDIA GRID K520 GPU installed in this system is
NVRM:  supported through the NVIDIA 367.xx Legacy drivers. Please
NVRM:  visit http://www.nvidia.com/object/unix.html for more
NVRM:  information.  The 375.39 NVIDIA driver will ignore
NVRM:  this GPU.  Continuing probe…

It was evident that at some point in the past, the NVIDIA driver had been upgraded to a version that now no longer supports the GRID K520 GPU card in the machine. Of course the first thought is to blame whoever had root access on the system. Let’s have a look at /var/log/apt/history.log then…

Start-Date: 2017-03-21  08:51:00
Commandline: /usr/bin/unattended-upgrade
Install: libcuda1-375:amd64 (375.39-0ubuntu0.16.04.1, automatic), nvidia-opencl-icd-375:amd64 (375.39-0ubuntu0.16.04.1, automatic), nvidia-375:amd64 (375.39-0ubuntu0.16.04.1, automatic)
Upgrade: libc6-dev:amd64 (2.23-0ubuntu5, 2.23-0ubuntu6), libcuda1-367:amd64 (367.57-0ubuntu0.16.04.1, 375.39-0ubuntu0.16.04.1), libc6:amd64 (2.23-0ubuntu5, 2.23-0ubuntu6), locales:amd64 (2.23-0ubuntu5, 2.23-0ubuntu6), libc-bin:amd64 (2.23-0ubuntu5, 2.23-0ubuntu6), libc6-
i386:amd64 (2.23-0ubuntu5, 2.23-0ubuntu6), libc-dev-bin:amd64 (2.23-0ubuntu5, 2.23-0ubuntu6), multiarch-support:amd64 (2.23-0ubuntu5, 2.23-0ubuntu6), libfreetype6:amd64 (2.6.1-0.1ubuntu2, 2.6.1-0.1ubuntu2.1), nvidia-opencl-icd-367:amd64 (367.57-0ubuntu0.16.04.1, 375.39-0
ubuntu0.16.04.1), nvidia-367:amd64 (367.57-0ubuntu0.16.04.1, 375.39-0ubuntu0.16.04.1)
End-Date: 2017-03-21  08:52:28

There we go, it was the unattended-upgrade feature of Ubuntu that’s upgrading NVIDIA drivers to an unsupported version for AWS G2 GPU machines.

To fix this, since version 367 of NVIDIA is no longer available in the Ubuntu archives, it has to be obtained as a build artifact. It’s not the cleanest way, but it would seem that the quickest way to resolve this is to apt-get remove nvidia-375, and any dependencies, and then install the build artifacts from https://launchpad.net/~ubuntu-security/+archive/ubuntu/ppa/+build/11078476


apt-get remove libcuda1-375 nvidia-opencl-icd-375 nvidia-375 nvidia-cuda-toolkit

wget https://launchpad.net/~ubuntu-security/+archive/ubuntu/ppa/+build/11078476/+files/nvidia-367_367.57-0ubuntu0.16.04.1_amd64.deb

wget https://launchpad.net/~ubuntu-security/+archive/ubuntu/ppa/+build/11078476/+files/nvidia-opencl-icd-367_367.57-0ubuntu0.16.04.1_amd64.deb

wget https://launchpad.net/~ubuntu-security/+archive/ubuntu/ppa/+build/11078476/+files/libcuda1-367_367.57-0ubuntu0.16.04.1_amd64.deb

dpkg -i –auto-deconfigure libcuda1-367_367.57-0ubuntu0.16.04.1_amd64.deb nvidia-opencl-icd-367_367.57-0ubuntu0.16.04.1_amd64.deb nvidia-367_367.57-0ubuntu0.16.04.1_amd64.deb

If there are any lingering versions of a package that depends on nvidia-375, uninstall it, rinse and repeat, and re-install it. It most likely does not depend on -375 explicitly, but a metapackage provided by -375, which we’re providing instead from -365

Once the core -367 packages are installed and happy, check dmesg to make sure the GPU has been discovered, and then reinstall nvidia-cuda-toolkit and any other packages. Assuming all goes well, you can now test your software against the installed package suit.

If things are working as expected, simply mark your now critical packages as held in order to prevent them from being upgraded again

apt-mark hold libcuda1-367 nvidia-367 nvidia-opencl-icd-367

This has been reported to Canonical at https://bugs.launchpad.net/ubuntu/+source/nvidia-graphics-drivers-375/+bug/1674666

Server side geofencing with Owntracks, Node-Red and Domoticz

Where to start?

The first challenge was getting data from my phone on public networks to my private MQTT server. At home I run Mosquitto for handling any message brokering, particularly with Domoticz and Node-Red pushing messages around.

I won’t go into the details, but suffice to say I have Mosquitto at home, and Mosquitto on a server I rent in OVH. The one in OVH is TLS, and protected by a username and password. It is this server to which Owntracks is configured to push messages to.

In turn, the two Mosquitto servers are bridged, as per http://e.verything.co/post/62163759361/bridging-two-mqtt-brokers and http://owntracks.org/booklet/guide/bridge/ in order for the topic to which the phone publishes to be available internally at home.

The end result of this is the periodic announcement of my phones location on my internal home network

mqttitude/bagpuss_thecat/galaxys2 {“_type”: “location”, “lat”: “55.9182683”, “lon”: “-4.2232088”, “tst”: “1457045018”, “acc”: “20.0”, “batt”: “48”}

From here, it gets ingested into Node-Red by firstly subscribing to the mqttitude/bagpuss_thecat/galaxys2 topic, then the JSON is parsed out, and then it’s processed by a couple of node-red-node-geofence nodes in order to determine if the phone is in a certain location or not. These simply return the msg.location.isat parameter if the device matches any of the geofences.

Depending on the status of the .isat parameter, I then use the multiple messages feature of node-red to send messages to each of my Domoticz switches to alter their state.

if ( msg.location.isat == "Home") {
var home = { payload:'{"idx":181,"nvalue":1}' };
var work = { payload:'{"idx":180,"nvalue":0}' };
} else if ( msg.location.isat == "Work") {
var home = { payload:'{"idx":181,"nvalue":0}' };
var work = { payload:'{"idx":180,"nvalue":1}' };
} else {
var home = { payload:'{"idx":181,"nvalue":0}' };
var work = { payload:'{"idx":180,"nvalue":0}' };
return [ [ work, home ] ];

As you can see from the above code, the Domoticz IDX of the switch to say that I’m at work is 180, Home is 181, and I can then use those dummy switch states in Domoticz to do additional logic within the home automation system.


UPDATE: 08/08/2017

As requested, a copy of the flow. I haven’t used it for a while now, since moving to http://home-assistant.io with native Owntracks support, but it might prove useful.

Geofencing, with node-red

[{“id”:”ceb5e9b3.255318″,”type”:”mqtt-broker”,”z”:””,”broker”:”homeauto.vpn.glasgownet.com”,”port”:”1883″,”clientid”:””,”usetls”:false,”compatmode”:true,”keepalive”:”15″,”cleansession”:true,”willTopic”:””,”willQos”:”0″,”willPayload”:””,”birthTopic”:””,”birthQos”:”0″,”birthPayload”:””},{“id”:”5d41030f.a2ba8c”,”type”:”mqtt in”,”z”:”e55a6d11.377b9″,”name”:”KyleG Owntracks”,”topic”:”owntracks/bagpuss/a0001″,”broker”:”ceb5e9b3.255318″,”x”:121,”y”:107,”wires”:[[“d256ba45.4be048”]]},{“id”:”a2dace61.598″,”type”:”mqtt out”,”z”:”e55a6d11.377b9″,”name”:”domoticz/in”,”topic”:”domoticz/in”,”qos”:””,”retain”:””,”broker”:”ceb5e9b3.255318″,”x”:957,”y”:112,”wires”:[]},{“id”:”52f3dc6d.f8fbd4″,”type”:”geofence”,”z”:”e55a6d11.377b9″,”name”:”Home”,”mode”:”circle”,”inside”:”true”,”rad”:88.99011032254676,”points”:[],”centre”:{“latitude”:55.918150666279054,”longitude”:-4.223449230194092},”x”:480,”y”:64,”wires”:[[“b2213e67.26d87″,”4961a9e.b165358”]]},{“id”:”d256ba45.4be048″,”type”:”function”,”z”:”e55a6d11.377b9″,”name”:”Lat/Long”,”func”:”msg.location = JSON.parse(msg.payload);\n\nreturn msg;”,”outputs”:1,”noerr”:0,”x”:309,”y”:107,”wires”:[[“52f3dc6d.f8fbd4″,”2415d034.e094a”,”154cf4bc.0c969b”,”b3a50cee.841fd”,”cd886406.0e8ea8″]]},{“id”:”b2213e67.26d87″,”type”:”function”,”z”:”e55a6d11.377b9″,”name”:”Location selector”,”func”:”// Home == 10\n// Work == 20\n\nif ( msg.location.isat == \”Home\”) {\n var home = { payload:'{\”idx\”:181,\”nvalue\”:1}’ };\n var work = { payload:'{\”idx\”:180,\”nvalue\”:0}’ };\n} else if ( msg.location.isat == \”Work\”) {\n var home = { payload:'{\”idx\”:181,\”nvalue\”:0}’ };\n var work = { payload:'{\”idx\”:180,\”nvalue\”:1}’ };\n} else {\n var home = { payload:'{\”idx\”:181,\”nvalue\”:0}’ };\n var work = { payload:'{\”idx\”:180,\”nvalue\”:0}’ };\n}\n\n\nreturn [ [ work, home ] ];”,”outputs”:”1″,”noerr”:0,”x”:708,”y”:113,”wires”:[[“a2dace61.598″,”7d37ae41.94953”]]},{“id”:”2415d034.e094a”,”type”:”geofence”,”z”:”e55a6d11.377b9″,”name”:”Work”,”mode”:”circle”,”inside”:”true”,”rad”:691.5530147043348,”points”:[],”centre”:{“latitude”:55.756722472194724,”longitude”:-4.288358688354492},”x”:476,”y”:140,”wires”:[[“b2213e67.26d87″,”4961a9e.b165358”]]},{“id”:”4961a9e.b165358″,”type”:”debug”,”z”:”e55a6d11.377b9″,”name”:””,”active”:true,”console”:”false”,”complete”:”location.isat”,”x”:706,”y”:65,”wires”:[]},{“id”:”7d37ae41.94953″,”type”:”debug”,”z”:”e55a6d11.377b9″,”name”:”Domotic payload toggles”,”active”:true,”console”:”false”,”complete”:”payload”,”x”:997,”y”:69,”wires”:[]},{“id”:”154cf4bc.0c969b”,”type”:”geofence”,”z”:”e55a6d11.377b9″,”name”:”Canteen”,”mode”:”circle”,”inside”:”true”,”rad”:16.778117069341608,”points”:[],”centre”:{“latitude”:55.756552675540114,”longitude”:-4.287972450256348},”x”:489.3333435058594,”y”:203.33333587646484,”wires”:[[“d4136e7.f6cfc9”]]},{“id”:”d4136e7.f6cfc9″,”type”:”mqtt out”,”z”:”e55a6d11.377b9″,”name”:””,”topic”:”testing/canteen”,”qos”:””,”retain”:””,”broker”:”ceb5e9b3.255318″,”x”:720.3333740234375,”y”:206.33334350585938,”wires”:[]},{“id”:”332b5b84.1a89e4″,”type”:”file”,”z”:”e55a6d11.377b9″,”name”:”location”,”filename”:”/tmp/location.csv”,”appendNewline”:true,”createDir”:false,”overwriteFile”:”false”,”x”:711.3333435058594,”y”:294.33333587646484,”wires”:[]},{“id”:”b3a50cee.841fd”,”type”:”function”,”z”:”e55a6d11.377b9″,”name”:”csvify”,”func”:”//msg.timestamp = new Date().toISOString();\n\nvar now = new Date(); \nvar year = now.getFullYear();\nvar month = now.getMonth()+1; \nvar day = now.getDate();\nvar hour = now.getHours();\nvar minute = now.getMinutes();\nvar second = now.getSeconds(); \nif(month.toString().length == 1) {\nvar month = ‘0’+month;\n}\nif(day.toString().length == 1) {\nvar day = ‘0’+day;\n} \nif(hour.toString().length == 1) {\nvar hour = ‘0’+hour;\n}\nif(minute.toString().length == 1) {\nvar minute = ‘0’+minute;\n}\nif(second.toString().length == 1) {\nvar second = ‘0’+second;\n} \nmsg.timestamp = year+’-‘+month+’-‘+day+’ ‘+hour+’:’+minute+’:’+second;\n\n\nmsg.parameters = JSON.parse(msg.payload);\n\nmsg.payload = msg.timestamp + ‘,’ + msg.parameters.lat + ‘,’ + msg.parameters.lon;\n\nreturn msg;”,”outputs”:1,”noerr”:0,”x”:489.8333435058594,”y”:275.33333587646484,”wires”:[[“332b5b84.1a89e4”]]},{“id”:”cd886406.0e8ea8″,”type”:”debug”,”z”:”e55a6d11.377b9″,”name”:””,”active”:false,”console”:”false”,”complete”:”location.lat”,”x”:265,”y”:248,”wires”:[]}]


1-wire, Node-Red, Domoticz & Grafana

Recently I posted a shiny graph of my garage temperature after I’d put a car with a hot engine in there. The spikes were fairly pronounced, and it was possibly to see where I’d left the door open whilst I worked on the car, before going for a test drive in the evening.

I was subsequently asked…

tl;dr 1-Wire -> ESP8266 -> MQTT -> Node-Red -> MQTT -> Domoticz -> MQTT -> Node-Red -> InfluxDB -> Grafana

It starts out simply enough, with a string of DS18B20 1-wire sensors hooked up to a WeMos D1 Mini NodeMCU board. On that board, there’s a copy of https://github.com/kylegordon/mqtt_esp8266_ds1820_arduino flashed onto, and it scans the bus periodically, reads the values, and publishes them to an MQTT broker. Each ROM ID (1-wire device) gets its own topic, and a plain number is published to the relevant topic.

My home automation controller of choice is Domoticz , and it likes a particular flavour of JSON being published on the /domoticz/in topic. This is where Node-Red steps in to do a translation.

[{“id”:”aa0d4469.8e7458″,”type”:”mqtt in”,”z”:”d5caab33.2a3558″,”name”:”esp8266 on temp/#”,”topic”:”temp/#”,”qos”:”2″,”broker”:”66a92c76.9956d4″,”x”:117,”y”:349,”wires”:[[“5f4ec201.7bbdac”]]},{“id”:”5f4ec201.7bbdac”,”type”:”function”,”z”:”d5caab33.2a3558″,”name”:”Device to IDX”,”func”:”temp = msg.payload/16;\nrom_id = msg.topic.split(\”/\”)[1];\n\nmsg.payload = {};\nswitch (rom_id) {\n case \”28b8c81d300e5\”:\n msg.payload.idx = 186;\n break;\n case \”28ac871d300e4\”:\n msg.payload.idx = 187;\n break;\n}\nmsg.payload.rom_id = rom_id;\ntemp = temp.toString();\nmsg.payload.svalue = temp;\n\n\nreturn msg;”,”outputs”:1,”noerr”:0,”x”:347,”y”:348,”wires”:[[“71da0e3.d7e8ff”]]},{“id”:”71da0e3.d7e8ff”,”type”:”mqtt out”,”z”:”d5caab33.2a3558″,”name”:””,”topic”:”domoticz/in”,”qos”:””,”retain”:””,”broker”:”66a92c76.9956d4″,”x”:535,”y”:349,”wires”:[]},{“id”:”66a92c76.9956d4″,”type”:”mqtt-broker”,”z”:””,”broker”:”homeauto.vpn.glasgownet.com”,”port”:”1883″,”clientid”:””,”usetls”:false,”compatmode”:true,”keepalive”:”15″,”cleansession”:true,”willTopic”:””,”willQos”:”0″,”willPayload”:””,”birthTopic”:””,”birthQos”:”0″,”birthPayload”:””}]

In short, this flow subscribes to all messages on temp/#, takes the payload and topic, and formulates a JSON message with the correct IDX. The IDX is the unique ID for a virtual device (in this case, a temperature sensor) in Domoticz. The JSON message is then published on /domoticz/in, where it is consumed by Domoticz and used for its own home automation purposes.

Now, every value of every device in Domoticz is also published on /domoticz/out. I use this for a few MQTT to Python services I run, but I also have another Node-Red flow that takes the Domoticz JSON messages and inserts them into InfluxDB. This flow was taken from here and relies on the node-red-contrib-influxdb node.

The rest is plain sailing really – there’s a Grafana install that is configured to use InfluxDB as a datasource. Grafana can extract the data using the IDX that’s mentioned above, and will display it in a nice fashion.

SELECT mean(“svalue1”) FROM “domoticz” WHERE “idx” = ‘171’ AND $timeFilter GROUP BY time($interval) fill(null)

Job done.

The Old Backnet

Spurred on by the Twitter discussion regarding the old Backnet network and Electron Club founding, I went for a rummage through some backups.

Fond memories of the Backnet Assigned Names And Number Authority, BANANA. Whilst I still use, I’ve expanded somewhat from the /27 to /24. My home network won’t fit on a /27 these days! Gordon is on, my parents on The legacy lives on a little, and still technically within the allocated BANANA range 🙂

Archive.org to the rescue! https://web.archive.org/web/20050421022318/http://wiki.backnet.org/BANANA/Addresses

Like I say, these are from backups. The file this came from was last modified in 2004!

Current Address Allocations

The majority of these addresses also route to the Backnet network

GlasgowNet currently runs on the IP range, and we have as well for overflow usage.

We also use AS numbers 65088 – 65103 from the private AS numbers range defined by IANA

You can see the current routing table on one of the routers at the looking glass – AS65089 – Kyle Gordon – AS65096 – Justin Hayes – AS65090 – Neil McKillop – ICM – AS65092 – Colin Petrie – Kenny Duffus – Andrew Elwell – AS65094 – William Anderson – AS65091 – Gordon Pearce – AS65093 – Stinkpad – AS65095 – Matthew Keay