about summary refs log tree commit diff
path: root/src/nm-initrd-generator
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2021-10-01 23:05:04 +0200
committerMichael Biebl <biebl@debian.org>2021-10-01 23:05:04 +0200
commite74c568b07b50b97873fb4ee1d776dedefbd54d6 (patch)
tree3469f17ea9af91f7ff169b890633bda68b0cf76e /src/nm-initrd-generator
parentbfe522304da217296e2a61040f58e35ec5d6f3f2 (diff)
New upstream version 1.32.12 upstream/1.32.12
Diffstat (limited to 'src/nm-initrd-generator')
-rw-r--r--src/nm-initrd-generator/meson.build47
-rw-r--r--src/nm-initrd-generator/nm-initrd-generator.c236
-rw-r--r--src/nm-initrd-generator/nm-initrd-generator.h46
-rw-r--r--src/nm-initrd-generator/nmi-cmdline-reader.c1416
-rw-r--r--src/nm-initrd-generator/nmi-dt-reader.c372
-rw-r--r--src/nm-initrd-generator/nmi-ibft-reader.c465
-rw-r--r--src/nm-initrd-generator/tests/meson.build43
-rw-r--r--src/nm-initrd-generator/tests/sysfs-bad-dns1/class/net/eth0/address1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/gateway1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/index1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/ip-addr1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/mac1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/origin1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/prefix-len1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/primary-dns1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/secondary-dns1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/subnet-mask1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/vlan1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-bad-dns1/firmware/ibft/initiator/initiator-name1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-bad-dns1/firmware/ibft/target0/index1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-bad-dns1/firmware/ibft/target0/ip-addr1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-bad-dns1/firmware/ibft/target0/lun1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-bad-dns1/firmware/ibft/target0/port1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-bad-dns1/firmware/ibft/target0/target-name1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-bad-dns2/class/net/eth0/address1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/gateway1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/index1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/ip-addr1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/mac1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/origin1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/prefix-len1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/primary-dns1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/secondary-dns1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/subnet-mask1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/vlan1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-bad-dns2/firmware/ibft/initiator/initiator-name1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-bad-dns2/firmware/ibft/target0/index1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-bad-dns2/firmware/ibft/target0/ip-addr1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-bad-dns2/firmware/ibft/target0/lun1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-bad-dns2/firmware/ibft/target0/port1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-bad-dns2/firmware/ibft/target0/target-name1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-bad-gateway/class/net/eth0/address1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/gateway1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/index1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/ip-addr1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/mac1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/origin1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/prefix-len1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/primary-dns1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/secondary-dns1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/subnet-mask1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/vlan1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-bad-gateway/firmware/ibft/initiator/initiator-name1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-bad-gateway/firmware/ibft/target0/index1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-bad-gateway/firmware/ibft/target0/ip-addr1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-bad-gateway/firmware/ibft/target0/lun1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-bad-gateway/firmware/ibft/target0/port1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-bad-gateway/firmware/ibft/target0/target-name1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-bad-ipaddr/class/net/eth0/address1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/gateway1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/index1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/ip-addr1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/mac1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/origin1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/prefix-len1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/primary-dns1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/secondary-dns1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/subnet-mask1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/vlan1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-bad-ipaddr/firmware/ibft/initiator/initiator-name1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-bad-ipaddr/firmware/ibft/target0/index1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-bad-ipaddr/firmware/ibft/target0/ip-addr1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-bad-ipaddr/firmware/ibft/target0/lun1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-bad-ipaddr/firmware/ibft/target0/port1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-bad-ipaddr/firmware/ibft/target0/target-name1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-dhcp/class/net/eth0/address1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-dhcp/class/net/eth1/address1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/ethernet0/gateway1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/ethernet0/index1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/ethernet0/mac1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/ethernet0/origin1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/ethernet0/primary-dns1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/ethernet0/secondary-dns1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/ethernet0/vlan1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/ethernet1/gateway1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/ethernet1/index1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/ethernet1/mac1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/ethernet1/origin1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/ethernet1/primary-dns1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/ethernet1/secondary-dns1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/ethernet1/vlan1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/initiator/initiator-name1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/target0/index1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/target0/ip-addr1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/target0/lun1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/target0/port1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/target0/target-name1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/target1/index1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/target1/ip-addr1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/target1/lun1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/target1/port1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/target1/target-name1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-dt-tftp/firmware/devicetree/base/chosen/bootpathbin0 -> 108 bytes
-rw-r--r--src/nm-initrd-generator/tests/sysfs-dt/firmware/devicetree/base/chosen/bootp-requestbin0 -> 273 bytes
-rw-r--r--src/nm-initrd-generator/tests/sysfs-dt/firmware/devicetree/base/chosen/bootp-responsebin0 -> 300 bytes
-rw-r--r--src/nm-initrd-generator/tests/sysfs-dt/firmware/devicetree/base/chosen/bootpathbin0 -> 37 bytes
-rw-r--r--src/nm-initrd-generator/tests/sysfs-dt/firmware/devicetree/base/chosen/broadcast-ip1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-dt/firmware/devicetree/base/chosen/client-ip2
-rw-r--r--src/nm-initrd-generator/tests/sysfs-dt/firmware/devicetree/base/chosen/client-namebin0 -> 9 bytes
-rw-r--r--src/nm-initrd-generator/tests/sysfs-dt/firmware/devicetree/base/chosen/domain-namebin0 -> 15 bytes
-rw-r--r--src/nm-initrd-generator/tests/sysfs-dt/firmware/devicetree/base/chosen/gateway-ip2
-rw-r--r--src/nm-initrd-generator/tests/sysfs-dt/firmware/devicetree/base/chosen/namebin0 -> 7 bytes
-rw-r--r--src/nm-initrd-generator/tests/sysfs-dt/firmware/devicetree/base/chosen/netmask-ipbin0 -> 4 bytes
-rw-r--r--src/nm-initrd-generator/tests/sysfs-dt/firmware/devicetree/base/chosen/root-pathbin0 -> 1 bytes
-rw-r--r--src/nm-initrd-generator/tests/sysfs-dt/firmware/devicetree/base/chosen/server-ip2
-rw-r--r--src/nm-initrd-generator/tests/sysfs-dt/firmware/devicetree/base/chosen/tftp-filebin0 -> 11 bytes
-rw-r--r--src/nm-initrd-generator/tests/sysfs-dt/firmware/devicetree/base/chosen/vendor-optionsbin0 -> 1 bytes
-rw-r--r--src/nm-initrd-generator/tests/sysfs-dt/firmware/devicetree/base/ethernet/device_typebin0 -> 8 bytes
-rw-r--r--src/nm-initrd-generator/tests/sysfs-dt/firmware/devicetree/base/ethernet/local-mac-address1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-dt/firmware/devicetree/base/ethernet/mac-address1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-dt/firmware/devicetree/base/ethernet/namebin0 -> 9 bytes
-rw-r--r--src/nm-initrd-generator/tests/sysfs-static/class/net/eth0/address1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-static/class/net/eth1/address1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/ethernet0/gateway1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/ethernet0/index1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/ethernet0/ip-addr1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/ethernet0/mac1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/ethernet0/origin1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/ethernet0/prefix-len1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/ethernet0/primary-dns1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/ethernet0/secondary-dns1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/ethernet0/subnet-mask1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/ethernet0/vlan1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/ethernet1/gateway1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/ethernet1/index1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/ethernet1/mac1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/ethernet1/origin1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/ethernet1/primary-dns1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/ethernet1/secondary-dns1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/ethernet1/vlan1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/initiator/initiator-name1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/target0/index1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/target0/ip-addr1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/target0/lun1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/target0/port1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/target0/target-name1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/target1/index1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/target1/ip-addr1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/target1/lun1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/target1/port1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/target1/target-name1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-vlan/class/net/eth0/address1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-vlan/firmware/ibft/ethernet0/index1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-vlan/firmware/ibft/ethernet0/ip-addr1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-vlan/firmware/ibft/ethernet0/mac1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-vlan/firmware/ibft/ethernet0/origin1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-vlan/firmware/ibft/ethernet0/prefix-len1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-vlan/firmware/ibft/ethernet0/subnet-mask1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-vlan/firmware/ibft/ethernet0/vlan1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-vlan/firmware/ibft/initiator/initiator-name1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-vlan/firmware/ibft/target0/index1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-vlan/firmware/ibft/target0/ip-addr1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-vlan/firmware/ibft/target0/lun1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-vlan/firmware/ibft/target0/port1
-rw-r--r--src/nm-initrd-generator/tests/sysfs-vlan/firmware/ibft/target0/target-name1
-rw-r--r--src/nm-initrd-generator/tests/sysfs/class/net/eth0/address1
-rw-r--r--src/nm-initrd-generator/tests/sysfs/class/net/eth2/address1
-rw-r--r--src/nm-initrd-generator/tests/sysfs/firmware/ibft/acpi_header/oem_id1
-rw-r--r--src/nm-initrd-generator/tests/sysfs/firmware/ibft/acpi_header/oem_table_id1
-rw-r--r--src/nm-initrd-generator/tests/sysfs/firmware/ibft/acpi_header/signature1
-rw-r--r--src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet0/dhcp1
-rw-r--r--src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet0/flags1
-rw-r--r--src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet0/gateway1
-rw-r--r--src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet0/hostname1
-rw-r--r--src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet0/index1
-rw-r--r--src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet0/ip-addr1
-rw-r--r--src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet0/mac1
-rw-r--r--src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet0/origin1
-rw-r--r--src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet0/prefix-len1
-rw-r--r--src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet0/primary-dns1
-rw-r--r--src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet0/secondary-dns1
-rw-r--r--src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet0/subnet-mask1
-rw-r--r--src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet0/vlan1
-rw-r--r--src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet2/dhcp1
-rw-r--r--src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet2/flags1
-rw-r--r--src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet2/gateway1
-rw-r--r--src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet2/hostname1
-rw-r--r--src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet2/index1
-rw-r--r--src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet2/ip-addr1
-rw-r--r--src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet2/mac1
-rw-r--r--src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet2/origin1
-rw-r--r--src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet2/prefix-len1
-rw-r--r--src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet2/primary-dns1
-rw-r--r--src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet2/secondary-dns1
-rw-r--r--src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet2/subnet-mask1
-rw-r--r--src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet2/vlan1
-rw-r--r--src/nm-initrd-generator/tests/sysfs/firmware/ibft/initiator/flags1
-rw-r--r--src/nm-initrd-generator/tests/sysfs/firmware/ibft/initiator/index1
-rw-r--r--src/nm-initrd-generator/tests/sysfs/firmware/ibft/initiator/initiator-name1
-rw-r--r--src/nm-initrd-generator/tests/sysfs/firmware/ibft/initiator/isns-server1
-rw-r--r--src/nm-initrd-generator/tests/sysfs/firmware/ibft/initiator/pri-radius-server1
-rw-r--r--src/nm-initrd-generator/tests/sysfs/firmware/ibft/initiator/sec-radius-server1
-rw-r--r--src/nm-initrd-generator/tests/sysfs/firmware/ibft/initiator/slp-server1
-rw-r--r--src/nm-initrd-generator/tests/sysfs/firmware/ibft/target0/chap-type1
-rw-r--r--src/nm-initrd-generator/tests/sysfs/firmware/ibft/target0/flags1
-rw-r--r--src/nm-initrd-generator/tests/sysfs/firmware/ibft/target0/index1
-rw-r--r--src/nm-initrd-generator/tests/sysfs/firmware/ibft/target0/ip-addr1
-rw-r--r--src/nm-initrd-generator/tests/sysfs/firmware/ibft/target0/lun1
-rw-r--r--src/nm-initrd-generator/tests/sysfs/firmware/ibft/target0/nic-assoc1
-rw-r--r--src/nm-initrd-generator/tests/sysfs/firmware/ibft/target0/port1
-rw-r--r--src/nm-initrd-generator/tests/sysfs/firmware/ibft/target2/chap-type1
-rw-r--r--src/nm-initrd-generator/tests/sysfs/firmware/ibft/target2/flags1
-rw-r--r--src/nm-initrd-generator/tests/sysfs/firmware/ibft/target2/index1
-rw-r--r--src/nm-initrd-generator/tests/sysfs/firmware/ibft/target2/ip-addr1
-rw-r--r--src/nm-initrd-generator/tests/sysfs/firmware/ibft/target2/lun1
-rw-r--r--src/nm-initrd-generator/tests/sysfs/firmware/ibft/target2/nic-assoc1
-rw-r--r--src/nm-initrd-generator/tests/sysfs/firmware/ibft/target2/port1
-rw-r--r--src/nm-initrd-generator/tests/sysfs/firmware/ibft/target2/target-name1
-rw-r--r--src/nm-initrd-generator/tests/test-cmdline-reader.c2552
-rw-r--r--src/nm-initrd-generator/tests/test-dt-reader.c143
-rw-r--r--src/nm-initrd-generator/tests/test-ibft-reader.c302
221 files changed, 5823 insertions, 0 deletions
diff --git a/src/nm-initrd-generator/meson.build b/src/nm-initrd-generator/meson.build
new file mode 100644
index 00000000..080fe7e4
--- /dev/null
+++ b/src/nm-initrd-generator/meson.build
@@ -0,0 +1,47 @@
+# SPDX-License-Identifier: LGPL-2.1-or-later
+
+libnmi_core = static_library(
+  'nmi-core',
+  sources: files(
+    'nmi-cmdline-reader.c',
+    'nmi-dt-reader.c',
+    'nmi-ibft-reader.c',
+  ),
+  include_directories: [
+    src_inc,
+    top_inc,
+  ],
+  dependencies: [
+    libnm_core_public_dep,
+  ],
+)
+
+executable(
+  'nm-initrd-generator',
+  'nm-initrd-generator.c',
+  include_directories: [
+    src_inc,
+    top_inc,
+  ],
+  dependencies: [
+    libnm_core_public_dep,
+  ],
+  link_with: [
+    libnmi_core,
+    libnm_core_aux_intern,
+    libnm_core_impl,
+    libnm_crypto,
+    libnm_platform,
+    libnm_base,
+    libnm_systemd_shared,
+    libnm_udev_aux,
+    libnm_log_core,
+    libnm_glib_aux,
+    libnm_std_aux,
+    libc_siphash,
+  ],
+  link_args: ldflags_linker_script_binary,
+  link_depends: linker_script_binary,
+  install: true,
+  install_dir: nm_libexecdir,
+)
diff --git a/src/nm-initrd-generator/nm-initrd-generator.c b/src/nm-initrd-generator/nm-initrd-generator.c
new file mode 100644
index 00000000..b78808b2
--- /dev/null
+++ b/src/nm-initrd-generator/nm-initrd-generator.c
@@ -0,0 +1,236 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ */
+
+#include "libnm-core-impl/nm-default-libnm-core.h"
+
+#include "nm-initrd-generator.h"
+
+#include "libnm-base/nm-config-base.h"
+#include "libnm-core-intern/nm-core-internal.h"
+#include "libnm-core-intern/nm-keyfile-internal.h"
+#include "libnm-glib-aux/nm-io-utils.h"
+#include "libnm-log-core/nm-logging.h"
+
+/*****************************************************************************/
+
+#define _NMLOG(level, domain, ...)                                 \
+    nm_log((level),                                                \
+           (domain),                                               \
+           NULL,                                                   \
+           NULL,                                                   \
+           "initrd-generator: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__) \
+               _NM_UTILS_MACRO_REST(__VA_ARGS__))
+
+/*****************************************************************************/
+
+static void
+output_conn(gpointer key, gpointer value, gpointer user_data)
+{
+    const char *          basename        = key;
+    NMConnection *        connection      = value;
+    char *                connections_dir = user_data;
+    nm_auto_unref_keyfile GKeyFile *file  = NULL;
+    gs_free char *                  data  = NULL;
+    gs_free_error GError *error           = NULL;
+    gsize                 len;
+    NMSetting *           setting;
+
+    setting = nm_setting_user_new();
+    nm_connection_add_setting(connection, setting);
+    nm_setting_user_set_data(NM_SETTING_USER(setting),
+                             NM_USER_TAG_ORIGIN,
+                             "nm-initrd-generator",
+                             NULL);
+
+    if (!nm_connection_normalize(connection, NULL, NULL, &error))
+        goto err_out;
+
+    file = nm_keyfile_write(connection, NM_KEYFILE_HANDLER_FLAGS_NONE, NULL, NULL, &error);
+    if (file == NULL)
+        goto err_out;
+
+    data = g_key_file_to_data(file, &len, &error);
+    if (!data)
+        goto err_out;
+
+    if (connections_dir) {
+        gs_free char *filename      = NULL;
+        gs_free char *full_filename = NULL;
+
+        filename      = nm_keyfile_utils_create_filename(basename, TRUE);
+        full_filename = g_build_filename(connections_dir, filename, NULL);
+
+        if (!nm_utils_file_set_contents(full_filename, data, len, 0600, NULL, NULL, &error))
+            goto err_out;
+    } else
+        g_print("\n*** Connection '%s' ***\n\n%s", basename, data);
+
+    return;
+err_out:
+    g_print("%s\n", error->message);
+}
+
+#define DEFAULT_SYSFS_DIR       "/sys"
+#define DEFAULT_INITRD_DATA_DIR NMRUNDIR "/initrd"
+#define DEFAULT_RUN_CONFIG_DIR  NMRUNDIR "/conf.d"
+
+int
+main(int argc, char *argv[])
+{
+    GHashTable *       connections;
+    gs_free char *     connections_dir  = NULL;
+    gs_free char *     initrd_dir       = NULL;
+    gs_free char *     sysfs_dir        = NULL;
+    gs_free char *     run_config_dir   = NULL;
+    gboolean           dump_to_stdout   = FALSE;
+    gs_strfreev char **remaining        = NULL;
+    GOptionEntry       option_entries[] = {
+        {"connections-dir",
+         'c',
+         0,
+         G_OPTION_ARG_FILENAME,
+         &connections_dir,
+         "Output connection directory",
+         NM_KEYFILE_PATH_NAME_RUN},
+        {"initrd-data-dir",
+         'i',
+         0,
+         G_OPTION_ARG_FILENAME,
+         &initrd_dir,
+         "Output initrd data directory",
+         DEFAULT_INITRD_DATA_DIR},
+        {"sysfs-dir",
+         'd',
+         0,
+         G_OPTION_ARG_FILENAME,
+         &sysfs_dir,
+         "The sysfs mount point",
+         DEFAULT_SYSFS_DIR},
+        {"run-config-dir",
+         'r',
+         0,
+         G_OPTION_ARG_FILENAME,
+         &run_config_dir,
+         "Output config directory",
+         DEFAULT_RUN_CONFIG_DIR},
+        {"stdout",
+         's',
+         0,
+         G_OPTION_ARG_NONE,
+         &dump_to_stdout,
+         "Dump connections to standard output",
+         NULL},
+        {G_OPTION_REMAINING, '\0', 0, G_OPTION_ARG_STRING_ARRAY, &remaining, NULL, NULL},
+        {NULL}};
+    nm_auto_free_option_context GOptionContext *option_context = NULL;
+    gs_free_error GError *error                                = NULL;
+    gs_free char *        hostname                             = NULL;
+    int                   errsv;
+    gint64                carrier_timeout_sec = 0;
+
+    option_context = g_option_context_new(
+        "-- [ip=...] [rd.route=...] [bridge=...] [bond=...] [team=...] [vlan=...] "
+        "[bootdev=...] [nameserver=...] [rd.peerdns=...] [rd.bootif=...] [BOOTIF=...] "
+        "[rd.znet=...] [rd.net.timeout.carrier=...] ... ");
+
+    g_option_context_set_summary(option_context, "Generate early NetworkManager configuration.");
+    g_option_context_set_description(
+        option_context,
+        "This tool scans the command line for options relevant to network\n"
+        "configuration and creates configuration files for an early instance\n"
+        "of NetworkManager run from the initial ramdisk during early boot.");
+    g_option_context_add_main_entries(option_context, option_entries, GETTEXT_PACKAGE);
+
+    if (!g_option_context_parse(option_context, &argc, &argv, &error)) {
+        _LOGW(LOGD_CORE, "%s", error->message);
+        return 1;
+    }
+
+    if (!remaining) {
+        /* No arguments, no networking. Don't bother. */
+        return 0;
+    }
+
+    if (!connections_dir)
+        connections_dir = g_strdup(NM_KEYFILE_PATH_NAME_RUN);
+    if (!sysfs_dir)
+        sysfs_dir = g_strdup(DEFAULT_SYSFS_DIR);
+    if (!initrd_dir)
+        initrd_dir = g_strdup(DEFAULT_INITRD_DATA_DIR);
+    if (!run_config_dir)
+        run_config_dir = g_strdup(DEFAULT_RUN_CONFIG_DIR);
+
+    connections = nmi_cmdline_reader_parse(sysfs_dir,
+                                           (const char *const *) remaining,
+                                           &hostname,
+                                           &carrier_timeout_sec);
+
+    if (dump_to_stdout) {
+        nm_clear_g_free(&connections_dir);
+        nm_clear_g_free(&initrd_dir);
+        nm_clear_g_free(&run_config_dir);
+        if (hostname)
+            g_print("\n*** Hostname '%s' ***\n", hostname);
+        if (carrier_timeout_sec != 0)
+            g_print("\n*** Carrier Wait Timeout %" G_GINT64_FORMAT " sec ***\n",
+                    carrier_timeout_sec);
+    } else {
+        if (g_mkdir_with_parents(connections_dir, 0755) != 0) {
+            errsv = errno;
+            _LOGW(LOGD_CORE, "%s: %s", connections_dir, nm_strerror_native(errsv));
+            return 1;
+        }
+        if (g_mkdir_with_parents(initrd_dir, 0755) != 0) {
+            errsv = errno;
+            _LOGW(LOGD_CORE, "%s: %s", initrd_dir, nm_strerror_native(errsv));
+            return 1;
+        }
+        if (g_mkdir_with_parents(run_config_dir, 0755) != 0) {
+            errsv = errno;
+            _LOGW(LOGD_CORE, "%s: %s", run_config_dir, nm_strerror_native(errsv));
+            return 1;
+        }
+
+        if (hostname) {
+            gs_free char *hostname_file = NULL;
+            gs_free char *data          = NULL;
+
+            hostname_file = g_strdup_printf("%s/hostname", initrd_dir);
+            data          = g_strdup_printf("%s\n", hostname);
+
+            if (!g_file_set_contents(hostname_file, data, strlen(data), &error)) {
+                _LOGW(LOGD_CORE, "%s: %s", hostname_file, error->message);
+                return 1;
+            }
+        }
+        if (carrier_timeout_sec != 0) {
+            nm_auto_unref_keyfile GKeyFile *keyfile  = NULL;
+            gs_free char *                  filename = NULL;
+
+            keyfile = g_key_file_new();
+            g_key_file_set_list_separator(keyfile, NM_CONFIG_KEYFILE_LIST_SEPARATOR);
+            filename = g_strdup_printf("%s/15-carrier-timeout.conf", run_config_dir);
+
+            g_key_file_set_value(keyfile,
+                                 NM_CONFIG_KEYFILE_GROUPPREFIX_DEVICE "-15-carrier-timeout",
+                                 NM_CONFIG_KEYFILE_KEY_MATCH_DEVICE,
+                                 "*");
+            g_key_file_set_int64(keyfile,
+                                 NM_CONFIG_KEYFILE_GROUPPREFIX_DEVICE "-15-carrier-timeout",
+                                 NM_CONFIG_KEYFILE_KEY_DEVICE_CARRIER_WAIT_TIMEOUT,
+                                 carrier_timeout_sec * 1000);
+
+            if (!g_key_file_save_to_file(keyfile, filename, &error)) {
+                _LOGW(LOGD_CORE, "%s: %s", filename, error->message);
+                return 1;
+            }
+        }
+    }
+
+    g_hash_table_foreach(connections, output_conn, connections_dir);
+    g_hash_table_destroy(connections);
+
+    return 0;
+}
diff --git a/src/nm-initrd-generator/nm-initrd-generator.h b/src/nm-initrd-generator/nm-initrd-generator.h
new file mode 100644
index 00000000..2ec52a01
--- /dev/null
+++ b/src/nm-initrd-generator/nm-initrd-generator.h
@@ -0,0 +1,46 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2014, 2018 Red Hat, Inc.
+ */
+
+#ifndef __NM_INITRD_GENERATOR_H__
+#define __NM_INITRD_GENERATOR_H__
+
+#include "nm-connection.h"
+#include "nm-utils.h"
+
+#define NMI_WAIT_DEVICE_TIMEOUT_MSEC 60000
+#define NMI_IP_REQUIRED_TIMEOUT_MSEC 20000
+
+static inline int
+get_ip_address_family(const char *str, gboolean with_prefix)
+{
+    int addr_family;
+
+    if (!str)
+        return AF_UNSPEC;
+
+    if (with_prefix) {
+        if (nm_utils_parse_inaddr_prefix_bin(AF_UNSPEC, str, &addr_family, NULL, NULL))
+            return addr_family;
+    } else {
+        if (nm_utils_parse_inaddr_bin(AF_UNSPEC, str, &addr_family, NULL))
+            return addr_family;
+    }
+
+    return AF_UNSPEC;
+}
+
+GHashTable *nmi_ibft_read(const char *sysfs_dir);
+
+gboolean
+nmi_ibft_update_connection_from_nic(NMConnection *connection, GHashTable *nic, GError **error);
+
+NMConnection *nmi_dt_reader_parse(const char *sysfs_dir);
+
+GHashTable *nmi_cmdline_reader_parse(const char *       sysfs_dir,
+                                     const char *const *argv,
+                                     char **            hostname,
+                                     gint64 *           carrier_timeout_sec);
+
+#endif /* __NM_INITRD_GENERATOR_H__ */
diff --git a/src/nm-initrd-generator/nmi-cmdline-reader.c b/src/nm-initrd-generator/nmi-cmdline-reader.c
new file mode 100644
index 00000000..a8501336
--- /dev/null
+++ b/src/nm-initrd-generator/nmi-cmdline-reader.c
@@ -0,0 +1,1416 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ */
+
+#include "libnm-core-impl/nm-default-libnm-core.h"
+
+#include <linux/if_ether.h>
+#include <linux/if_infiniband.h>
+
+#include "libnm-glib-aux/nm-uuid.h"
+#include "libnm-log-core/nm-logging.h"
+#include "libnm-core-intern/nm-core-internal.h"
+#include "nm-initrd-generator.h"
+#include "libnm-systemd-shared/nm-sd-utils-shared.h"
+
+/*****************************************************************************/
+
+#define _NMLOG(level, domain, ...)                               \
+    nm_log((level),                                              \
+           (domain),                                             \
+           NULL,                                                 \
+           NULL,                                                 \
+           "cmdline-reader: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__) \
+               _NM_UTILS_MACRO_REST(__VA_ARGS__))
+
+/*****************************************************************************/
+
+typedef struct {
+    GHashTable *  hash;
+    GPtrArray *   array;
+    GPtrArray *   vlan_parents;
+    GHashTable *  explicit_ip_connections;
+    NMConnection *bootdev_connection; /* connection for bootdev=$ifname */
+    NMConnection *default_connection; /* connection not bound to any ifname */
+    char *        hostname;
+
+    /* Parameters to be set for all connections */
+    gboolean ignore_auto_dns;
+    int      dhcp_timeout;
+    char *   dhcp4_vci;
+
+    gint64 carrier_timeout_sec;
+} Reader;
+
+static Reader *
+reader_new(void)
+{
+    Reader *reader;
+
+    reader  = g_slice_new(Reader);
+    *reader = (Reader){
+        .hash = g_hash_table_new_full(nm_str_hash, g_str_equal, g_free, g_object_unref),
+        .explicit_ip_connections =
+            g_hash_table_new_full(nm_direct_hash, NULL, g_object_unref, NULL),
+        .vlan_parents = g_ptr_array_new_with_free_func(g_free),
+        .array        = g_ptr_array_new(),
+    };
+
+    return reader;
+}
+
+static GHashTable *
+reader_destroy(Reader *reader, gboolean free_hash)
+{
+    gs_unref_hashtable GHashTable *hash = NULL;
+
+    g_ptr_array_unref(reader->array);
+    g_ptr_array_unref(reader->vlan_parents);
+    g_hash_table_unref(reader->explicit_ip_connections);
+    hash = g_steal_pointer(&reader->hash);
+    nm_clear_g_free(&reader->hostname);
+    nm_clear_g_free(&reader->dhcp4_vci);
+    nm_g_slice_free(reader);
+    if (!free_hash)
+        return g_steal_pointer(&hash);
+    return NULL;
+}
+
+static NMConnection *
+reader_add_connection(Reader *reader, const char *name, NMConnection *connection_take)
+{
+    char *name_dup;
+
+    name_dup = g_strdup(name);
+    if (g_hash_table_insert(reader->hash, name_dup, connection_take))
+        g_ptr_array_add(reader->array, name_dup);
+
+    return connection_take;
+}
+
+/* Returns a new connection owned by the reader */
+static NMConnection *
+reader_create_connection(Reader *                 reader,
+                         const char *             basename,
+                         const char *             id,
+                         const char *             ifname,
+                         const char *             mac,
+                         const char *             type_name,
+                         NMConnectionMultiConnect multi_connect)
+{
+    NMConnection *connection;
+    NMSetting *   setting;
+
+    connection = reader_add_connection(reader, basename, nm_simple_connection_new());
+
+    /* Start off assuming dynamic IP configurations. */
+
+    setting = nm_setting_ip4_config_new();
+    nm_connection_add_setting(connection, setting);
+    g_object_set(setting,
+                 NM_SETTING_IP_CONFIG_METHOD,
+                 NM_SETTING_IP4_CONFIG_METHOD_AUTO,
+                 NM_SETTING_IP_CONFIG_MAY_FAIL,
+                 TRUE,
+                 NM_SETTING_IP_CONFIG_IGNORE_AUTO_DNS,
+                 reader->ignore_auto_dns,
+                 NM_SETTING_IP_CONFIG_DHCP_TIMEOUT,
+                 reader->dhcp_timeout,
+                 NM_SETTING_IP4_CONFIG_DHCP_VENDOR_CLASS_IDENTIFIER,
+                 reader->dhcp4_vci,
+                 NM_SETTING_IP_CONFIG_REQUIRED_TIMEOUT,
+                 NMI_IP_REQUIRED_TIMEOUT_MSEC,
+                 NULL);
+
+    setting = nm_setting_ip6_config_new();
+    nm_connection_add_setting(connection, setting);
+    g_object_set(setting,
+                 NM_SETTING_IP_CONFIG_METHOD,
+                 NM_SETTING_IP4_CONFIG_METHOD_AUTO,
+                 NM_SETTING_IP_CONFIG_MAY_FAIL,
+                 TRUE,
+                 NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE,
+                 (int) NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64,
+                 NM_SETTING_IP_CONFIG_IGNORE_AUTO_DNS,
+                 reader->ignore_auto_dns,
+                 NM_SETTING_IP_CONFIG_DHCP_TIMEOUT,
+                 reader->dhcp_timeout,
+                 NULL);
+
+    setting = nm_setting_connection_new();
+    nm_connection_add_setting(connection, setting);
+    g_object_set(setting,
+                 NM_SETTING_CONNECTION_ID,
+                 id,
+                 NM_SETTING_CONNECTION_UUID,
+                 nm_uuid_generate_random_str_a(),
+                 NM_SETTING_CONNECTION_INTERFACE_NAME,
+                 ifname,
+                 NM_SETTING_CONNECTION_TYPE,
+                 type_name,
+                 NM_SETTING_CONNECTION_MULTI_CONNECT,
+                 multi_connect,
+                 NM_SETTING_CONNECTION_AUTOCONNECT_RETRIES,
+                 1,
+                 NULL);
+
+    if (nm_streq0(type_name, NM_SETTING_INFINIBAND_SETTING_NAME)) {
+        setting = nm_setting_infiniband_new();
+        nm_connection_add_setting(connection, setting);
+        g_object_set(setting, NM_SETTING_INFINIBAND_TRANSPORT_MODE, "datagram", NULL);
+    }
+
+    if (mac) {
+        if (nm_streq0(type_name, NM_SETTING_INFINIBAND_SETTING_NAME)) {
+            setting = (NMSetting *) nm_connection_get_setting_infiniband(connection);
+            g_object_set(setting, NM_SETTING_INFINIBAND_MAC_ADDRESS, mac, NULL);
+        } else {
+            setting = nm_setting_wired_new();
+            nm_connection_add_setting(connection, setting);
+            g_object_set(setting, NM_SETTING_WIRED_MAC_ADDRESS, mac, NULL);
+        }
+    }
+
+    return connection;
+}
+
+static NMConnection *
+reader_get_default_connection(Reader *reader)
+{
+    NMConnection *con;
+
+    if (!reader->default_connection) {
+        con = reader_create_connection(reader,
+                                       "default_connection",
+                                       "Wired Connection",
+                                       NULL,
+                                       NULL,
+                                       NM_SETTING_WIRED_SETTING_NAME,
+                                       NM_CONNECTION_MULTI_CONNECT_MULTIPLE);
+        nm_connection_add_setting(con, nm_setting_wired_new());
+        reader->default_connection = con;
+    }
+    return reader->default_connection;
+}
+
+static NMConnection *
+reader_get_connection(Reader *    reader,
+                      const char *iface_spec,
+                      const char *type_name,
+                      gboolean    create_if_missing)
+{
+    NMConnection *connection = NULL;
+    NMSetting *   setting;
+    const char *  ifname = NULL;
+    gs_free char *mac    = NULL;
+
+    if (iface_spec) {
+        if (nm_utils_is_valid_iface_name(iface_spec, NULL))
+            ifname = iface_spec;
+        else {
+            mac = nm_utils_hwaddr_canonical(iface_spec, -1);
+            if (!mac)
+                _LOGW(LOGD_CORE, "invalid interface '%s'", iface_spec);
+        }
+    }
+
+    if (!ifname && !mac) {
+        NMConnection *       candidate;
+        NMSettingConnection *s_con;
+        guint                i;
+
+        /*
+         * If ifname was not given, we'll match the connection by type.
+         * If the type was not given either, then we're happy with any connection but slaves.
+         * This is so that things like "bond=bond0:eth1,eth2 nameserver=1.3.3.7 end up
+         * slapping the nameserver to the most reasonable connection (bond0).
+         */
+        for (i = 0; i < reader->array->len; i++) {
+            candidate = g_hash_table_lookup(reader->hash, reader->array->pdata[i]);
+            s_con     = nm_connection_get_setting_connection(candidate);
+
+            if (type_name == NULL && nm_setting_connection_get_master(s_con) == NULL) {
+                connection = candidate;
+                break;
+            }
+
+            if (type_name != NULL
+                && nm_streq(nm_setting_connection_get_connection_type(s_con), type_name)) {
+                connection = candidate;
+                break;
+            }
+        }
+    } else
+        connection = g_hash_table_lookup(reader->hash, (gpointer) ifname ?: mac);
+
+    if (!connection) {
+        if (!create_if_missing)
+            return NULL;
+
+        if (!type_name) {
+            if (NM_STR_HAS_PREFIX(ifname, "ib")
+                || (mac && nm_utils_hwaddr_valid(mac, INFINIBAND_ALEN)))
+                type_name = NM_SETTING_INFINIBAND_SETTING_NAME;
+            else
+                type_name = NM_SETTING_WIRED_SETTING_NAME;
+        }
+
+        connection = reader_create_connection(reader,
+                                              ifname ?: mac,
+                                              ifname ?: (mac ?: "Wired Connection"),
+                                              ifname,
+                                              mac,
+                                              type_name,
+                                              NM_CONNECTION_MULTI_CONNECT_SINGLE);
+    }
+    setting = (NMSetting *) nm_connection_get_setting_connection(connection);
+
+    if (type_name) {
+        g_object_set(setting, NM_SETTING_CONNECTION_TYPE, type_name, NULL);
+        if (!nm_connection_get_setting_by_name(connection, type_name)) {
+            setting = g_object_new(nm_setting_lookup_type(type_name), NULL);
+            nm_connection_add_setting(connection, setting);
+        }
+    }
+
+    return connection;
+}
+
+static char *
+get_word(char **argument, const char separator)
+{
+    char *word;
+    int   nest = 0;
+
+    if (*argument == NULL)
+        return NULL;
+
+    if (**argument == '[') {
+        nest++;
+        (*argument)++;
+    }
+
+    word = *argument;
+
+    while (**argument != '\0') {
+        if (nest && **argument == ']') {
+            **argument = '\0';
+            (*argument)++;
+            nest--;
+            continue;
+        }
+
+        if (nest == 0 && **argument == separator) {
+            **argument = '\0';
+            (*argument)++;
+            break;
+        }
+        (*argument)++;
+    }
+
+    return *word ? word : NULL;
+}
+
+static void
+connection_set(NMConnection *connection,
+               const char *  setting_name,
+               const char *  property,
+               const char *  value)
+{
+    NMSetting *              setting;
+    GType                    setting_type;
+    nm_auto_unref_gtypeclass GObjectClass *object_class = NULL;
+    GParamSpec *                           spec;
+
+    setting_type = nm_setting_lookup_type(setting_name);
+    object_class = g_type_class_ref(setting_type);
+    spec         = g_object_class_find_property(object_class, property);
+    nm_assert(spec);
+
+    setting = nm_connection_get_setting_by_name(connection, setting_name);
+    if (!setting) {
+        setting = g_object_new(setting_type, NULL);
+        nm_connection_add_setting(connection, setting);
+    }
+
+    if (G_IS_PARAM_SPEC_UINT(spec)) {
+        guint v;
+
+        v = _nm_utils_ascii_str_to_int64(value, 10, 0, G_MAXUINT, 0);
+        if (errno || !nm_g_object_set_property_uint(G_OBJECT(setting), property, v, NULL)) {
+            _LOGW(LOGD_CORE,
+                  "Could not set property '%s.%s' to '%s'",
+                  setting_name,
+                  property,
+                  value);
+        }
+    } else if (G_IS_PARAM_SPEC_STRING(spec))
+        g_object_set(setting, property, value, NULL);
+    else
+        _LOGW(LOGD_CORE, "Don't know how to set '%s' of %s", property, setting_name);
+}
+
+static void
+reader_read_all_connections_from_fw(Reader *reader, const char *sysfs_dir)
+{
+    gs_unref_hashtable GHashTable *ibft = NULL;
+    NMConnection *                 dt_connection;
+    const char *                   mac;
+    GHashTable *                   nic;
+    const char *                   index;
+    GError *                       error = NULL;
+    guint                          i, length;
+    gs_free const char **          keys = NULL;
+
+    ibft = nmi_ibft_read(sysfs_dir);
+    keys = nm_utils_strdict_get_keys(ibft, TRUE, &length);
+
+    for (i = 0; i < length; i++) {
+        gs_unref_object NMConnection *connection = NULL;
+        gs_free char *                name       = NULL;
+
+        mac        = keys[i];
+        nic        = g_hash_table_lookup(ibft, mac);
+        connection = nm_simple_connection_new();
+        index      = g_hash_table_lookup(nic, "index");
+        if (!index) {
+            _LOGW(LOGD_CORE, "Ignoring an iBFT entry without an index");
+            continue;
+        }
+
+        if (!nmi_ibft_update_connection_from_nic(connection, nic, &error)) {
+            _LOGW(LOGD_CORE, "Unable to merge iBFT configuration: %s", error->message);
+            g_error_free(error);
+            continue;
+        }
+
+        name = g_strdup_printf("ibft%s", index);
+        reader_add_connection(reader, name, g_steal_pointer(&connection));
+    }
+
+    dt_connection = nmi_dt_reader_parse(sysfs_dir);
+    if (dt_connection)
+        reader_add_connection(reader, "ofw", dt_connection);
+}
+
+static void
+reader_parse_ip(Reader *reader, const char *sysfs_dir, char *argument)
+{
+    NMConnection *       connection;
+    NMSettingConnection *s_con;
+    NMSettingIPConfig *  s_ip4 = NULL, *s_ip6 = NULL;
+    gs_unref_hashtable GHashTable *ibft = NULL;
+    const char *                   tmp;
+    const char *                   tmp2;
+    const char *                   kind                       = NULL;
+    const char *                   client_ip                  = NULL;
+    const char *                   peer                       = NULL;
+    const char *                   gateway_ip                 = NULL;
+    const char *                   netmask                    = NULL;
+    const char *                   client_hostname            = NULL;
+    const char *                   iface_spec                 = NULL;
+    const char *                   mtu                        = NULL;
+    const char *                   macaddr                    = NULL;
+    int                            client_ip_family           = AF_UNSPEC;
+    int                            client_ip_prefix           = -1;
+    gboolean                       clear_ip4_required_timeout = TRUE;
+    const char *                   dns[2]                     = {
+        NULL,
+        NULL,
+    };
+    int dns_addr_family[2] = {
+        AF_UNSPEC,
+        AF_UNSPEC,
+    };
+    int     i;
+    GError *error = NULL;
+
+    if (!*argument)
+        return;
+
+    tmp = get_word(&argument, ':');
+    if (!*argument) {
+        /* ip={dhcp|on|any|dhcp6|auto6|link6|ibft} */
+        kind = tmp;
+    } else {
+        tmp2 = get_word(&argument, ':');
+        if (NM_IN_STRSET(tmp2,
+                         "none",
+                         "off",
+                         "dhcp",
+                         "single-dhcp",
+                         "on"
+                         "any",
+                         "dhcp6",
+                         "auto",
+                         "auto6",
+                         "link6",
+                         "ibft")) {
+            /* <ifname>:{none|off|dhcp|on|any|dhcp6|auto|auto6|link6|ibft} */
+            iface_spec = tmp;
+            kind       = tmp2;
+        } else {
+            /* <client-IP>:[<peer>]:<gateway-IP>:<netmask>:<client_hostname>:<kind> */
+            client_ip = tmp;
+            if (client_ip) {
+                client_ip_family = get_ip_address_family(client_ip, TRUE);
+                if (client_ip_family == AF_UNSPEC) {
+                    _LOGW(LOGD_CORE, "Invalid IP address '%s'.", client_ip);
+                    return;
+                }
+            }
+
+            peer            = tmp2;
+            gateway_ip      = get_word(&argument, ':');
+            netmask         = get_word(&argument, ':');
+            client_hostname = get_word(&argument, ':');
+            iface_spec      = get_word(&argument, ':');
+            kind            = get_word(&argument, ':');
+        }
+
+        if (client_hostname && !nm_sd_hostname_is_valid(client_hostname, FALSE))
+            client_hostname = NULL;
+
+        if (client_hostname) {
+            g_free(reader->hostname);
+            reader->hostname = g_strdup(client_hostname);
+        }
+
+        tmp                = get_word(&argument, ':');
+        dns_addr_family[0] = get_ip_address_family(tmp, FALSE);
+        if (dns_addr_family[0] != AF_UNSPEC) {
+            dns[0] = tmp;
+            dns[1] = get_word(&argument, ':');
+            if (dns[1]) {
+                dns_addr_family[1] = get_ip_address_family(dns[1], FALSE);
+                if (dns_addr_family[1] == AF_UNSPEC)
+                    _LOGW(LOGD_CORE, "Ignoring invalid DNS server: '%s'.", dns[1]);
+                if (*argument)
+                    _LOGW(LOGD_CORE, "Ignoring extra: '%s'.", argument);
+            }
+        } else {
+            mtu     = tmp;
+            macaddr = argument;
+        }
+    }
+
+    if (iface_spec == NULL && NM_IN_STRSET(kind, "fw", "ibft")) {
+        reader_read_all_connections_from_fw(reader, sysfs_dir);
+        return;
+    }
+
+    /* Parsing done, construct the NMConnection. */
+    if (iface_spec)
+        connection = reader_get_connection(reader, iface_spec, NULL, TRUE);
+    else
+        connection = reader_get_default_connection(reader);
+
+    g_hash_table_add(reader->explicit_ip_connections, g_object_ref(connection));
+
+    s_con = nm_connection_get_setting_connection(connection);
+    s_ip4 = nm_connection_get_setting_ip4_config(connection);
+    s_ip6 = nm_connection_get_setting_ip6_config(connection);
+
+    if (netmask && *netmask) {
+        gboolean is_ipv4 = client_ip_family == AF_INET;
+        NMIPAddr addr;
+
+        if (is_ipv4 && nm_utils_parse_inaddr_bin(AF_INET, netmask, NULL, &addr))
+            client_ip_prefix = nm_utils_ip4_netmask_to_prefix(addr.addr4);
+        else
+            client_ip_prefix = _nm_utils_ascii_str_to_int64(netmask, 10, 0, is_ipv4 ? 32 : 128, -1);
+
+        if (client_ip_prefix == -1)
+            _LOGW(LOGD_CORE, "Invalid IP mask: %s", netmask);
+    }
+
+    /* Static IP configuration might be present. */
+    if (client_ip && *client_ip) {
+        NMIPAddress *address = NULL;
+        NMIPAddr     addr;
+
+        if (nm_utils_parse_inaddr_prefix_bin(client_ip_family,
+                                             client_ip,
+                                             NULL,
+                                             &addr,
+                                             client_ip_prefix == -1 ? &client_ip_prefix : NULL)) {
+            if (client_ip_prefix == -1) {
+                switch (client_ip_family) {
+                case AF_INET:
+                    client_ip_prefix = _nm_utils_ip4_get_default_prefix(addr.addr4);
+                    break;
+                case AF_INET6:
+                    client_ip_prefix = 64;
+                    break;
+                }
+            }
+
+            address = nm_ip_address_new_binary(client_ip_family,
+                                               &addr.addr_ptr,
+                                               client_ip_prefix,
+                                               &error);
+            if (!address) {
+                _LOGW(LOGD_CORE, "Invalid address '%s': %s", client_ip, error->message);
+                g_clear_error(&error);
+            }
+        } else
+            nm_assert_not_reached();
+
+        if (address) {
+            /* We don't want to have multiple devices up with the
+             * same static address. */
+            g_object_set(s_con,
+                         NM_SETTING_CONNECTION_MULTI_CONNECT,
+                         NM_CONNECTION_MULTI_CONNECT_SINGLE,
+                         NULL);
+            switch (client_ip_family) {
+            case AF_INET:
+                g_object_set(s_ip4,
+                             NM_SETTING_IP_CONFIG_METHOD,
+                             NM_SETTING_IP4_CONFIG_METHOD_MANUAL,
+                             NM_SETTING_IP_CONFIG_MAY_FAIL,
+                             FALSE,
+                             NULL);
+                nm_setting_ip_config_add_address(s_ip4, address);
+                break;
+            case AF_INET6:
+                g_object_set(s_ip6,
+                             NM_SETTING_IP_CONFIG_METHOD,
+                             NM_SETTING_IP4_CONFIG_METHOD_MANUAL,
+                             NM_SETTING_IP_CONFIG_MAY_FAIL,
+                             FALSE,
+                             NULL);
+                nm_setting_ip_config_add_address(s_ip6, address);
+                break;
+            default:
+                nm_assert_not_reached();
+                break;
+            }
+            nm_ip_address_unref(address);
+        }
+    }
+
+    /* Dynamic IP configuration configured explicitly. */
+    if (NM_IN_STRSET(kind, "none", "off")) {
+        if (nm_setting_ip_config_get_num_addresses(s_ip6) == 0) {
+            g_object_set(s_ip6,
+                         NM_SETTING_IP_CONFIG_METHOD,
+                         NM_SETTING_IP6_CONFIG_METHOD_DISABLED,
+                         NULL);
+        }
+        if (nm_setting_ip_config_get_num_addresses(s_ip4) == 0) {
+            g_object_set(s_ip4,
+                         NM_SETTING_IP_CONFIG_METHOD,
+                         NM_SETTING_IP4_CONFIG_METHOD_DISABLED,
+                         NULL);
+        }
+    } else if (NM_IN_STRSET(kind, "dhcp", "single-dhcp")) {
+        g_object_set(s_ip4,
+                     NM_SETTING_IP_CONFIG_METHOD,
+                     NM_SETTING_IP4_CONFIG_METHOD_AUTO,
+                     NM_SETTING_IP_CONFIG_MAY_FAIL,
+                     FALSE,
+                     NULL);
+        if (nm_setting_ip_config_get_num_addresses(s_ip6) == 0) {
+            g_object_set(s_ip6,
+                         NM_SETTING_IP_CONFIG_METHOD,
+                         NM_SETTING_IP6_CONFIG_METHOD_AUTO,
+                         NULL);
+        }
+    } else if (NM_IN_STRSET(kind, "auto6", "dhcp6")) {
+        g_object_set(s_ip6,
+                     NM_SETTING_IP_CONFIG_METHOD,
+                     NM_SETTING_IP6_CONFIG_METHOD_AUTO,
+                     NM_SETTING_IP_CONFIG_MAY_FAIL,
+                     FALSE,
+                     NULL);
+        if (nm_setting_ip_config_get_num_addresses(s_ip4) == 0) {
+            g_object_set(s_ip4,
+                         NM_SETTING_IP_CONFIG_METHOD,
+                         NM_SETTING_IP4_CONFIG_METHOD_DISABLED,
+                         NULL);
+        }
+    } else if (nm_streq0(kind, "link6")) {
+        g_object_set(s_ip6,
+                     NM_SETTING_IP_CONFIG_METHOD,
+                     NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL,
+                     NM_SETTING_IP_CONFIG_MAY_FAIL,
+                     FALSE,
+                     NULL);
+        if (nm_setting_ip_config_get_num_addresses(s_ip4) == 0) {
+            g_object_set(s_ip4,
+                         NM_SETTING_IP_CONFIG_METHOD,
+                         NM_SETTING_IP4_CONFIG_METHOD_DISABLED,
+                         NULL);
+        }
+    } else if (nm_streq0(kind, "ibft")) {
+        NMSettingWired *s_wired;
+        const char *    mac = NULL;
+        const char *    ifname;
+        gs_free char *  mac_free     = NULL;
+        gs_free char *  address_path = NULL;
+        GHashTable *    nic          = NULL;
+
+        if ((s_wired = nm_connection_get_setting_wired(connection))
+            && (mac = nm_setting_wired_get_mac_address(s_wired))) {
+            /* got mac from the connection */
+        } else if ((ifname = nm_connection_get_interface_name(connection))) {
+            /* read it from sysfs */
+            address_path = g_build_filename(sysfs_dir, "class", "net", ifname, "address", NULL);
+            if (g_file_get_contents(address_path, &mac_free, NULL, &error)) {
+                g_strchomp(mac_free);
+                mac = mac_free;
+            } else {
+                _LOGW(LOGD_CORE, "Can't get a MAC address for %s: %s", ifname, error->message);
+                g_clear_error(&error);
+            }
+        }
+
+        if (mac) {
+            gs_free char *mac_up = NULL;
+
+            mac_up = g_ascii_strup(mac, -1);
+            ibft   = nmi_ibft_read(sysfs_dir);
+            nic    = g_hash_table_lookup(ibft, mac_up);
+            if (!nic)
+                _LOGW(LOGD_CORE, "No iBFT NIC for %s (%s)", iface_spec, mac_up);
+        }
+
+        if (nic) {
+            if (!nmi_ibft_update_connection_from_nic(connection, nic, &error)) {
+                _LOGW(LOGD_CORE, "Unable to merge iBFT configuration: %s", error->message);
+                g_clear_error(&error);
+            }
+        }
+    } else {
+        clear_ip4_required_timeout = FALSE;
+    }
+
+    if (clear_ip4_required_timeout)
+        g_object_set(s_ip4, NM_SETTING_IP_CONFIG_REQUIRED_TIMEOUT, -1, NULL);
+
+    if (peer && *peer)
+        _LOGW(LOGD_CORE, "Ignoring peer: %s (not implemented)\n", peer);
+
+    if (gateway_ip && *gateway_ip) {
+        switch (get_ip_address_family(gateway_ip, FALSE)) {
+        case AF_INET:
+            g_object_set(s_ip4, NM_SETTING_IP_CONFIG_GATEWAY, gateway_ip, NULL);
+            break;
+        case AF_INET6:
+            g_object_set(s_ip6, NM_SETTING_IP_CONFIG_GATEWAY, gateway_ip, NULL);
+            break;
+        default:
+            _LOGW(LOGD_CORE, "Invalid gateway: %s", gateway_ip);
+            break;
+        }
+    }
+
+    if (client_hostname && *client_hostname) {
+        g_object_set(s_ip4, NM_SETTING_IP_CONFIG_DHCP_HOSTNAME, client_hostname, NULL);
+        g_object_set(s_ip6, NM_SETTING_IP_CONFIG_DHCP_HOSTNAME, client_hostname, NULL);
+    }
+
+    for (i = 0; i < 2; i++) {
+        if (dns_addr_family[i] == AF_UNSPEC)
+            break;
+        nm_assert(nm_utils_ipaddr_is_valid(dns_addr_family[i], dns[i]));
+        nm_setting_ip_config_add_dns(NM_IS_IPv4(dns_addr_family[i]) ? s_ip4 : s_ip6, dns[i]);
+    }
+
+    if (mtu && *mtu)
+        connection_set(connection, NM_SETTING_WIRED_SETTING_NAME, NM_SETTING_WIRED_MTU, mtu);
+
+    if (macaddr && *macaddr)
+        connection_set(connection,
+                       NM_SETTING_WIRED_SETTING_NAME,
+                       NM_SETTING_WIRED_CLONED_MAC_ADDRESS,
+                       macaddr);
+}
+
+static void
+reader_parse_master(Reader *reader, char *argument, const char *type_name, const char *default_name)
+{
+    NMConnection *       connection;
+    NMSettingConnection *s_con;
+    gs_free char *       master_to_free = NULL;
+    const char *         master;
+    char *               slaves;
+    const char *         slave;
+    char *               opts;
+    const char *         mtu = NULL;
+
+    master = get_word(&argument, ':');
+    if (!master)
+        master = master_to_free = g_strdup_printf("%s0", default_name ?: type_name);
+    slaves = get_word(&argument, ':');
+
+    connection = reader_get_connection(reader, master, type_name, TRUE);
+    s_con      = nm_connection_get_setting_connection(connection);
+    master     = nm_setting_connection_get_uuid(s_con);
+
+    if (nm_streq(type_name, NM_SETTING_BRIDGE_SETTING_NAME)) {
+        NMSettingBridge *s_bridge = nm_connection_get_setting_bridge(connection);
+
+        /* Avoid the forwarding delay */
+        g_object_set(s_bridge, NM_SETTING_BRIDGE_STP, FALSE, NULL);
+    } else if (nm_streq(type_name, NM_SETTING_BOND_SETTING_NAME)) {
+        NMSettingBond *s_bond = nm_connection_get_setting_bond(connection);
+
+        opts = get_word(&argument, ':');
+        while (opts && *opts) {
+            gs_free_error GError *error = NULL;
+            char *                opt;
+            const char *          opt_name;
+
+            opt      = get_word(&opts, ',');
+            opt_name = get_word(&opt, '=');
+
+            if (!_nm_setting_bond_validate_option(opt_name, opt, &error)) {
+                _LOGW(LOGD_CORE,
+                      "Ignoring invalid bond option: %s%s%s = %s%s%s: %s",
+                      NM_PRINT_FMT_QUOTE_STRING(opt_name),
+                      NM_PRINT_FMT_QUOTE_STRING(opt),
+                      error->message);
+                continue;
+            }
+            nm_setting_bond_add_option(s_bond, opt_name, opt);
+        }
+
+        mtu = get_word(&argument, ':');
+    }
+
+    if (mtu)
+        connection_set(connection, NM_SETTING_WIRED_SETTING_NAME, NM_SETTING_WIRED_MTU, mtu);
+
+    do {
+        slave = get_word(&slaves, ',');
+        if (slave == NULL)
+            slave = "eth0";
+
+        connection = reader_get_connection(reader, slave, NULL, TRUE);
+        s_con      = nm_connection_get_setting_connection(connection);
+        g_object_set(s_con,
+                     NM_SETTING_CONNECTION_SLAVE_TYPE,
+                     type_name,
+                     NM_SETTING_CONNECTION_MASTER,
+                     master,
+                     NULL);
+    } while (slaves && *slaves != '\0');
+
+    if (argument && *argument)
+        _LOGW(LOGD_CORE, "Ignoring extra: '%s'.", argument);
+}
+
+static void
+reader_add_routes(Reader *reader, GPtrArray *array)
+{
+    guint i;
+
+    for (i = 0; i < array->len; i++) {
+        NMConnection *     connection = NULL;
+        const char *       net;
+        const char *       gateway;
+        const char *       interface;
+        int                family       = AF_UNSPEC;
+        NMIPAddr           net_addr     = {};
+        NMIPAddr           gateway_addr = {};
+        int                net_prefix   = -1;
+        NMIPRoute *        route;
+        NMSettingIPConfig *s_ip;
+        char *             argument;
+        gs_free_error GError *error = NULL;
+
+        argument  = array->pdata[i];
+        net       = get_word(&argument, ':');
+        gateway   = get_word(&argument, ':');
+        interface = get_word(&argument, ':');
+
+        if (interface)
+            connection = reader_get_connection(reader, interface, NULL, TRUE);
+        if (!connection)
+            connection = reader->bootdev_connection;
+        if (!connection)
+            connection = reader_get_connection(reader, interface, NULL, FALSE);
+        if (!connection)
+            connection = reader_get_default_connection(reader);
+
+        if (net && *net) {
+            if (!nm_utils_parse_inaddr_prefix_bin(family, net, &family, &net_addr, &net_prefix)) {
+                _LOGW(LOGD_CORE, "Unrecognized address: %s", net);
+                continue;
+            }
+        }
+
+        if (gateway && *gateway) {
+            if (!nm_utils_parse_inaddr_bin(family, gateway, &family, &gateway_addr)) {
+                _LOGW(LOGD_CORE, "Unrecognized address: %s", gateway);
+                continue;
+            }
+        }
+
+        switch (family) {
+        case AF_INET:
+            s_ip = nm_connection_get_setting_ip4_config(connection);
+            if (net_prefix == -1)
+                net_prefix = 32;
+            break;
+        case AF_INET6:
+            s_ip = nm_connection_get_setting_ip6_config(connection);
+            if (net_prefix == -1)
+                net_prefix = 128;
+            break;
+        default:
+            _LOGW(LOGD_CORE, "Unknown address family: %s", net);
+            continue;
+        }
+
+        route = nm_ip_route_new_binary(family,
+                                       &net_addr.addr_ptr,
+                                       net_prefix,
+                                       &gateway_addr.addr_ptr,
+                                       -1,
+                                       &error);
+        if (!route) {
+            g_warning("Invalid route '%s via %s': %s\n", net, gateway, error->message);
+            continue;
+        }
+
+        nm_setting_ip_config_add_route(s_ip, route);
+        nm_ip_route_unref(route);
+    }
+}
+
+static void
+reader_parse_vlan(Reader *reader, char *argument)
+{
+    NMConnection * connection;
+    NMSettingVlan *s_vlan;
+    const char *   vlan;
+    const char *   phy;
+    const char *   vlanid;
+
+    vlan = get_word(&argument, ':');
+    phy  = get_word(&argument, ':');
+
+    for (vlanid = vlan + strlen(vlan); vlanid > vlan; vlanid--) {
+        if (!g_ascii_isdigit(*(vlanid - 1)))
+            break;
+    }
+
+    connection = reader_get_connection(reader, vlan, NM_SETTING_VLAN_SETTING_NAME, TRUE);
+
+    s_vlan = nm_connection_get_setting_vlan(connection);
+    g_object_set(s_vlan,
+                 NM_SETTING_VLAN_PARENT,
+                 phy,
+                 NM_SETTING_VLAN_ID,
+                 (guint) _nm_utils_ascii_str_to_int64(vlanid, 10, 0, G_MAXUINT, G_MAXUINT),
+                 NULL);
+
+    if (argument && *argument)
+        _LOGW(LOGD_CORE, "Ignoring extra: '%s'.", argument);
+
+    if (!nm_strv_ptrarray_contains(reader->vlan_parents, phy))
+        g_ptr_array_add(reader->vlan_parents, g_strdup(phy));
+}
+
+static void
+reader_parse_ib_pkey(Reader *reader, char *argument)
+{
+    NMConnection *       connection;
+    NMSettingInfiniband *s_ib;
+    char *               ifname;
+    gs_free char *       parent = NULL;
+    char *               pkey;
+    gint64               pkey_int;
+
+    /* At the moment we only support ib.pkey=<parent>.<pkey>;
+     * in the future we want to possibly support other options:
+     * ib.pkey=<parent>.<pkey>:<option>:...
+     */
+    ifname = get_word(&argument, ':');
+    if (!ifname) {
+        _LOGW(LOGD_CORE, "ib.pkey= without argument");
+        return;
+    }
+
+    parent = g_strdup(ifname);
+    pkey   = strchr(parent, '.');
+    if (!pkey) {
+        _LOGW(LOGD_CORE, "No pkey found for '%s'", ifname);
+        return;
+    }
+
+    *pkey = '\0';
+    pkey++;
+
+    pkey_int = _nm_utils_ascii_str_to_int64(pkey, 16, 0, 0xFFFF, -1);
+    if (pkey_int == -1) {
+        _LOGW(LOGD_CORE, "Invalid pkey '%s'", pkey);
+        return;
+    }
+
+    connection = reader_get_connection(reader, ifname, NM_SETTING_INFINIBAND_SETTING_NAME, TRUE);
+
+    s_ib = nm_connection_get_setting_infiniband(connection);
+    g_object_set(s_ib,
+                 NM_SETTING_INFINIBAND_PARENT,
+                 parent,
+                 NM_SETTING_INFINIBAND_P_KEY,
+                 (int) pkey_int,
+                 NULL);
+
+    if (argument && *argument)
+        _LOGW(LOGD_CORE, "Ignoring extra: '%s' for ib.pkey=", argument);
+}
+
+static void
+reader_parse_rd_znet(Reader *reader, char *argument, gboolean net_ifnames)
+{
+    const char *    nettype;
+    const char *    subchannels[4] = {0, 0, 0, 0};
+    const char *    tmp;
+    gs_free char *  ifname = NULL;
+    const char *    prefix;
+    NMConnection *  connection;
+    NMSettingWired *s_wired;
+    static int      count_ctc = 0;
+    static int      count_eth = 0;
+    int             index;
+
+    nettype        = get_word(&argument, ',');
+    subchannels[0] = get_word(&argument, ',');
+    subchannels[1] = get_word(&argument, ',');
+
+    /* Without subchannels we can't univocally match
+     * a device. */
+    if (!subchannels[0] || !subchannels[1])
+        return;
+
+    if (nm_streq0(nettype, "ctc")) {
+        if (net_ifnames == TRUE) {
+            prefix = "sl";
+        } else {
+            prefix = "ctc";
+            index  = count_ctc++;
+        }
+    } else {
+        subchannels[2] = get_word(&argument, ',');
+        if (net_ifnames == TRUE) {
+            prefix = "en";
+        } else {
+            prefix = "eth";
+            index  = count_eth++;
+        }
+    }
+
+    if (net_ifnames == TRUE) {
+        const char *bus_id;
+        size_t      bus_id_len;
+        size_t      bus_id_start;
+
+        /* The following logic is taken from names_ccw() in systemd/src/udev/udev-builtin-net_id.c */
+        bus_id       = subchannels[0];
+        bus_id_len   = strlen(bus_id);
+        bus_id_start = strspn(bus_id, ".0");
+        bus_id += bus_id_start < bus_id_len ? bus_id_start : bus_id_len - 1;
+
+        ifname = g_strdup_printf("%sc%s", prefix, bus_id);
+    } else {
+        ifname = g_strdup_printf("%s%d", prefix, index);
+    }
+
+    connection = reader_get_connection(reader, ifname, NM_SETTING_WIRED_SETTING_NAME, FALSE);
+    if (!connection)
+        return;
+    s_wired = nm_connection_get_setting_wired(connection);
+    g_object_set(s_wired,
+                 NM_SETTING_WIRED_S390_NETTYPE,
+                 nettype,
+                 NM_SETTING_WIRED_S390_SUBCHANNELS,
+                 &subchannels,
+                 NULL);
+
+    while ((tmp = get_word(&argument, ',')) != NULL) {
+        const char *key;
+        char *      val;
+
+        val = strchr(tmp, '=');
+        if (!val) {
+            /* an invalid (or empty) entry. Ignore. */
+            continue;
+        }
+
+        key    = tmp;
+        val[0] = '\0';
+        val++;
+        if (!_nm_setting_wired_is_valid_s390_option(key)
+            || !_nm_setting_wired_is_valid_s390_option_value(key, val)) {
+            /* Invalid setting. Silently ignore, but also ensure we
+             * didn't already set it. */
+            nm_setting_wired_remove_s390_option(s_wired, key);
+        } else
+            nm_setting_wired_add_s390_option(s_wired, key, val);
+    }
+}
+
+static void
+reader_parse_ethtool(Reader *reader, char *argument)
+{
+    const char *    interface   = NULL;
+    NMConnection *  connection  = NULL;
+    NMSettingWired *s_wired     = NULL;
+    const char *    autoneg_str = NULL;
+    gboolean        autoneg     = FALSE;
+    const char *    speed_str   = NULL;
+    guint           speed       = 0;
+
+    interface = get_word(&argument, ':');
+    if (!interface) {
+        _LOGW(LOGD_CORE, "Impossible to set rd.ethtool options: invalid format");
+        return;
+    }
+
+    if (!*argument) {
+        _LOGW(LOGD_CORE, "Could not find rd.ethtool options to set");
+        return;
+    }
+
+    connection = reader_get_connection(reader, interface, NM_SETTING_WIRED_SETTING_NAME, TRUE);
+    s_wired    = nm_connection_get_setting_wired(connection);
+
+    autoneg_str = get_word(&argument, ':');
+    if (autoneg_str) {
+        autoneg = _nm_utils_ascii_str_to_bool(autoneg_str, -1);
+        if (autoneg == -1)
+            _LOGW(LOGD_CORE,
+                  "Invalid value for rd.ethtool.autoneg, rd.ethtool.autoneg was not set");
+        else
+            g_object_set(s_wired, NM_SETTING_WIRED_AUTO_NEGOTIATE, autoneg, NULL);
+    }
+    if (!*argument)
+        return;
+
+    speed_str = get_word(&argument, ':');
+    if (speed_str) {
+        speed = _nm_utils_ascii_str_to_int64(speed_str, 10, 0, G_MAXUINT32, -1);
+        if (speed == -1)
+            _LOGW(LOGD_CORE, "Invalid value for rd.ethtool.speed, rd.ethtool.speed was not set");
+        else
+            g_object_set(s_wired,
+                         NM_SETTING_WIRED_SPEED,
+                         speed,
+                         NM_SETTING_WIRED_DUPLEX,
+                         "full",
+                         NULL);
+    }
+
+    if (!*argument)
+        return;
+    else
+        _LOGW(LOGD_CORE,
+              "Invalid extra argument '%s' for rd.ethtool, this value was not set",
+              argument);
+}
+
+static void
+_normalize_conn(gpointer key, gpointer value, gpointer user_data)
+{
+    NMConnection *connection = value;
+
+    nm_connection_normalize(connection, NULL, NULL, NULL);
+}
+
+static void
+reader_add_nameservers(Reader *reader, GPtrArray *nameservers)
+{
+    NMConnection *     connection;
+    NMSettingIPConfig *s_ip;
+    GHashTableIter     iter;
+    int                addr_family;
+    const char *       ns;
+    guint              i;
+
+    for (i = 0; i < nameservers->len; i++) {
+        ns          = nameservers->pdata[i];
+        addr_family = get_ip_address_family(ns, FALSE);
+        if (addr_family == AF_UNSPEC) {
+            _LOGW(LOGD_CORE, "Unknown address family: %s", ns);
+            continue;
+        }
+
+        g_hash_table_iter_init(&iter, reader->hash);
+        while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &connection)) {
+            switch (addr_family) {
+            case AF_INET:
+                s_ip = nm_connection_get_setting_ip4_config(connection);
+                if (!NM_IN_STRSET(nm_setting_ip_config_get_method(s_ip),
+                                  NM_SETTING_IP4_CONFIG_METHOD_AUTO,
+                                  NM_SETTING_IP4_CONFIG_METHOD_MANUAL))
+                    continue;
+                break;
+            case AF_INET6:
+                s_ip = nm_connection_get_setting_ip6_config(connection);
+                if (!NM_IN_STRSET(nm_setting_ip_config_get_method(s_ip),
+                                  NM_SETTING_IP6_CONFIG_METHOD_AUTO,
+                                  NM_SETTING_IP6_CONFIG_METHOD_DHCP,
+                                  NM_SETTING_IP6_CONFIG_METHOD_MANUAL))
+                    continue;
+                break;
+            default:
+                nm_assert_not_reached();
+                continue;
+            }
+
+            nm_setting_ip_config_add_dns(s_ip, ns);
+        }
+    }
+}
+
+static void
+connection_set_needed(NMConnection *connection)
+{
+    NMSettingConnection *s_con;
+
+    s_con = nm_connection_get_setting_connection(connection);
+    if (!nm_streq0(nm_setting_connection_get_connection_type(s_con), NM_SETTING_WIRED_SETTING_NAME))
+        return;
+
+    g_object_set(s_con,
+                 NM_SETTING_CONNECTION_WAIT_DEVICE_TIMEOUT,
+                 (int) NMI_WAIT_DEVICE_TIMEOUT_MSEC,
+                 NULL);
+}
+
+static void
+connection_set_needed_cb(gpointer key, gpointer value, gpointer user_data)
+{
+    connection_set_needed(value);
+}
+
+GHashTable *
+nmi_cmdline_reader_parse(const char *       sysfs_dir,
+                         const char *const *argv,
+                         char **            hostname,
+                         gint64 *           carrier_timeout_sec)
+{
+    Reader *          reader;
+    const char *      tag;
+    gboolean          ignore_bootif          = FALSE;
+    gboolean          neednet                = FALSE;
+    gs_free char *    bootif_val             = NULL;
+    gs_free char *    bootdev                = NULL;
+    gboolean          net_ifnames            = TRUE;
+    gs_unref_ptrarray GPtrArray *nameservers = NULL;
+    gs_unref_ptrarray GPtrArray *routes      = NULL;
+    gs_unref_ptrarray GPtrArray *znets       = NULL;
+    int                          i;
+    guint64                      dhcp_timeout   = 90;
+    guint64                      dhcp_num_tries = 1;
+
+    reader = reader_new();
+
+    for (i = 0; argv[i]; i++) {
+        gs_free char *argument_clone = NULL;
+        char *        argument;
+
+        argument_clone = g_strdup(argv[i]);
+        argument       = argument_clone;
+
+        tag = get_word(&argument, '=');
+
+        if (!tag) {
+            /* pass */
+        } else if (nm_streq(tag, "net.ifnames"))
+            net_ifnames = !nm_streq(argument, "0");
+        else if (nm_streq(tag, "rd.peerdns"))
+            reader->ignore_auto_dns = !_nm_utils_ascii_str_to_bool(argument, TRUE);
+        else if (nm_streq(tag, "rd.net.timeout.dhcp")) {
+            if (nm_streq0(argument, "infinity")) {
+                dhcp_timeout = G_MAXINT32;
+            } else {
+                dhcp_timeout =
+                    _nm_utils_ascii_str_to_int64(argument, 10, 1, G_MAXINT32, dhcp_timeout);
+            }
+        } else if (nm_streq(tag, "rd.net.dhcp.retry")) {
+            dhcp_num_tries =
+                _nm_utils_ascii_str_to_int64(argument, 10, 1, G_MAXINT32, dhcp_num_tries);
+        } else if (nm_streq(tag, "rd.net.dhcp.vendor-class")) {
+            if (nm_utils_validate_dhcp4_vendor_class_id(argument, NULL))
+                nm_utils_strdup_reset(&reader->dhcp4_vci, argument);
+        } else if (nm_streq(tag, "rd.net.timeout.carrier")) {
+            reader->carrier_timeout_sec =
+                _nm_utils_ascii_str_to_int64(argument, 10, 0, G_MAXINT32, 0);
+        }
+    }
+
+    reader->dhcp_timeout = NM_CLAMP(dhcp_timeout * dhcp_num_tries, 1, G_MAXINT32);
+
+    for (i = 0; argv[i]; i++) {
+        gs_free char *argument_clone = NULL;
+        char *        argument;
+        char *        word;
+
+        argument_clone = g_strdup(argv[i]);
+        argument       = argument_clone;
+
+        tag = get_word(&argument, '=');
+        if (!tag) {
+            /* pass */
+        } else if (nm_streq(tag, "ip"))
+            reader_parse_ip(reader, sysfs_dir, argument);
+        else if (nm_streq(tag, "rd.route")) {
+            if (!routes)
+                routes = g_ptr_array_new_with_free_func(g_free);
+            g_ptr_array_add(routes, g_strdup(argument));
+        } else if (nm_streq(tag, "bridge"))
+            reader_parse_master(reader, argument, NM_SETTING_BRIDGE_SETTING_NAME, "br");
+        else if (nm_streq(tag, "bond"))
+            reader_parse_master(reader, argument, NM_SETTING_BOND_SETTING_NAME, NULL);
+        else if (nm_streq(tag, "team"))
+            reader_parse_master(reader, argument, NM_SETTING_TEAM_SETTING_NAME, NULL);
+        else if (nm_streq(tag, "vlan"))
+            reader_parse_vlan(reader, argument);
+        else if (nm_streq(tag, "ib.pkey"))
+            reader_parse_ib_pkey(reader, argument);
+        else if (nm_streq(tag, "bootdev")) {
+            g_free(bootdev);
+            bootdev = g_strdup(argument);
+        } else if (nm_streq(tag, "nameserver")) {
+            word = get_word(&argument, '\0');
+            if (word) {
+                if (!nameservers)
+                    nameservers = g_ptr_array_new_with_free_func(g_free);
+                g_ptr_array_add(nameservers, g_strdup(word));
+            }
+            if (argument && *argument)
+                _LOGW(LOGD_CORE, "Ignoring extra: '%s'.", argument);
+        } else if (nm_streq(tag, "rd.iscsi.ibft") && _nm_utils_ascii_str_to_bool(argument, TRUE))
+            reader_read_all_connections_from_fw(reader, sysfs_dir);
+        else if (nm_streq(tag, "rd.bootif"))
+            ignore_bootif = !_nm_utils_ascii_str_to_bool(argument, TRUE);
+        else if (nm_streq(tag, "rd.neednet"))
+            neednet = _nm_utils_ascii_str_to_bool(argument, TRUE);
+        else if (nm_streq(tag, "rd.znet")) {
+            if (!znets)
+                znets = g_ptr_array_new_with_free_func(g_free);
+            g_ptr_array_add(znets, g_strdup(argument));
+        } else if (g_ascii_strcasecmp(tag, "BOOTIF") == 0) {
+            nm_clear_g_free(&bootif_val);
+            bootif_val = g_strdup(argument);
+        } else if (nm_streq(tag, "rd.ethtool"))
+            reader_parse_ethtool(reader, argument);
+    }
+
+    for (i = 0; i < reader->vlan_parents->len; i++) {
+        NMConnection *     connection;
+        NMSettingIPConfig *s_ip;
+
+        /* Disable IP configuration for parent connections of VLANs,
+         * unless those interfaces were explicitly configured otherwise. */
+
+        connection = reader_get_connection(reader, reader->vlan_parents->pdata[i], NULL, TRUE);
+        if (!g_hash_table_contains(reader->explicit_ip_connections, connection)) {
+            s_ip = nm_connection_get_setting_ip4_config(connection);
+            if (s_ip) {
+                g_object_set(s_ip,
+                             NM_SETTING_IP_CONFIG_METHOD,
+                             NM_SETTING_IP4_CONFIG_METHOD_DISABLED,
+                             NULL);
+            }
+
+            s_ip = nm_connection_get_setting_ip6_config(connection);
+            if (s_ip) {
+                g_object_set(s_ip,
+                             NM_SETTING_IP_CONFIG_METHOD,
+                             NM_SETTING_IP6_CONFIG_METHOD_DISABLED,
+                             NULL);
+            }
+        }
+    }
+
+    if (ignore_bootif)
+        nm_clear_g_free(&bootif_val);
+    if (bootif_val) {
+        NMConnection *  connection;
+        NMSettingWired *s_wired;
+        const char *    bootif = bootif_val;
+        char            prefix[4];
+
+        if (!nm_utils_hwaddr_valid(bootif, ETH_ALEN)) {
+            strncpy(prefix, bootif, 3);
+            prefix[3] = '\0';
+
+            if (NM_IN_STRSET(prefix, "01-", "01:", "00-", "00:")
+                && nm_utils_hwaddr_valid(&bootif[3], ETH_ALEN)) {
+                /*
+                 * BOOTIF MAC address can be prefixed with a hardware type identifier.
+                 * "01" stays for "wired", "00" is also accepted as it means "undefined".
+                 * No others are known.
+                 */
+                bootif += 3;
+            }
+        }
+
+        connection = reader_get_connection(reader, NULL, NM_SETTING_WIRED_SETTING_NAME, FALSE);
+        if (!connection)
+            connection = reader_get_default_connection(reader);
+
+        s_wired = nm_connection_get_setting_wired(connection);
+
+        if (nm_connection_get_interface_name(connection)
+            || (nm_setting_wired_get_mac_address(s_wired)
+                && !nm_utils_hwaddr_matches(nm_setting_wired_get_mac_address(s_wired),
+                                            -1,
+                                            bootif,
+                                            -1))) {
+            connection = reader_create_connection(reader,
+                                                  "bootif_connection",
+                                                  "BOOTIF Connection",
+                                                  NULL,
+                                                  bootif,
+                                                  NM_SETTING_WIRED_SETTING_NAME,
+                                                  NM_CONNECTION_MULTI_CONNECT_SINGLE);
+        } else {
+            g_object_set(s_wired, NM_SETTING_WIRED_MAC_ADDRESS, bootif, NULL);
+        }
+    }
+
+    if (bootdev) {
+        NMConnection *connection;
+
+        connection                 = reader_get_connection(reader, bootdev, NULL, TRUE);
+        reader->bootdev_connection = connection;
+        connection_set_needed(connection);
+    }
+
+    if (neednet) {
+        if (g_hash_table_size(reader->hash) == 0) {
+            /* Make sure there's some connection. */
+            reader_get_default_connection(reader);
+        }
+
+        g_hash_table_foreach(reader->hash, connection_set_needed_cb, NULL);
+    }
+
+    if (routes)
+        reader_add_routes(reader, routes);
+
+    if (nameservers)
+        reader_add_nameservers(reader, nameservers);
+
+    if (znets) {
+        for (i = 0; i < znets->len; i++)
+            reader_parse_rd_znet(reader, znets->pdata[i], net_ifnames);
+    }
+
+    g_hash_table_foreach(reader->hash, _normalize_conn, NULL);
+
+    NM_SET_OUT(hostname, g_steal_pointer(&reader->hostname));
+
+    NM_SET_OUT(carrier_timeout_sec, reader->carrier_timeout_sec);
+
+    return reader_destroy(reader, FALSE);
+}
diff --git a/src/nm-initrd-generator/nmi-dt-reader.c b/src/nm-initrd-generator/nmi-dt-reader.c
new file mode 100644
index 00000000..99c149dc
--- /dev/null
+++ b/src/nm-initrd-generator/nmi-dt-reader.c
@@ -0,0 +1,372 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2019 Red Hat, Inc.
+ */
+
+#include "libnm-core-impl/nm-default-libnm-core.h"
+
+#include "nm-initrd-generator.h"
+
+#include <arpa/inet.h>
+#include <linux/if_ether.h>
+
+#include "libnm-log-core/nm-logging.h"
+#include "libnm-core-intern/nm-core-internal.h"
+
+/*****************************************************************************/
+
+#define _NMLOG(level, domain, ...) \
+    nm_log((level),                \
+           (domain),               \
+           NULL,                   \
+           NULL,                   \
+           "dt-reader: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__) _NM_UTILS_MACRO_REST(__VA_ARGS__))
+
+/*****************************************************************************/
+
+static gboolean
+dt_get_property(const char *base,
+                const char *dev,
+                const char *prop,
+                char **     contents,
+                size_t *    length)
+{
+    gs_free char *filename      = g_build_filename(base, dev, prop, NULL);
+    gs_free_error GError *error = NULL;
+
+    if (!g_file_test(filename, G_FILE_TEST_EXISTS))
+        return FALSE;
+
+    if (!contents)
+        return TRUE;
+
+    if (!g_file_get_contents(filename, contents, length, &error)) {
+        _LOGW(LOGD_CORE, "%s: Can not read the %s property: %s", dev, prop, error->message);
+        return FALSE;
+    }
+
+    return TRUE;
+}
+
+static NMIPAddress *
+dt_get_ipaddr_property(const char *base, const char *dev, const char *prop, int *family)
+{
+    gs_free char *buf = NULL;
+    size_t        len;
+    int           f;
+
+    if (!dt_get_property(base, dev, prop, &buf, &len))
+        return NULL;
+
+    f = nm_utils_addr_family_from_size(len);
+    if (f == AF_UNSPEC || (*family != AF_UNSPEC && *family != f)) {
+        _LOGW(LOGD_CORE, "%s: Address %s has unrecognized length (%zd)", dev, prop, len);
+        return NULL;
+    }
+
+    *family = f;
+    return nm_ip_address_new_binary(f, buf, 0, NULL);
+}
+
+static char *
+dt_get_hwaddr_property(const char *base, const char *dev, const char *prop)
+{
+    gs_free guint8 *buf = NULL;
+    size_t          len;
+
+    if (!dt_get_property(base, dev, prop, (char **) &buf, &len))
+        return NULL;
+
+    if (len != ETH_ALEN) {
+        _LOGW(LOGD_CORE, "%s: MAC address %s has unrecognized length (%zd)", dev, prop, len);
+        return NULL;
+    }
+
+    return g_strdup_printf("%02x:%02x:%02x:%02x:%02x:%02x",
+                           buf[0],
+                           buf[1],
+                           buf[2],
+                           buf[3],
+                           buf[4],
+                           buf[4]);
+}
+
+static NMIPAddress *
+str_addr(const char *str, int *family)
+{
+    NMIPAddr addr_bin;
+
+    if (!nm_utils_parse_inaddr_bin_full(*family, TRUE, str, family, &addr_bin)) {
+        _LOGW(LOGD_CORE, "Malformed IP address: '%s'", str);
+        return NULL;
+    }
+    return nm_ip_address_new_binary(*family, &addr_bin, 0, NULL);
+}
+
+NMConnection *
+nmi_dt_reader_parse(const char *sysfs_dir)
+{
+    gs_unref_object NMConnection *connection           = NULL;
+    gs_free char *                base                 = NULL;
+    gs_free char *                bootpath             = NULL;
+    gs_strfreev char **           tokens               = NULL;
+    char *                        path                 = NULL;
+    gboolean                      bootp                = FALSE;
+    const char *                  s_ipaddr             = NULL;
+    const char *                  s_netmask            = NULL;
+    const char *                  s_gateway            = NULL;
+    nm_auto_unref_ip_address NMIPAddress *ipaddr       = NULL;
+    nm_auto_unref_ip_address NMIPAddress *gateway      = NULL;
+    const char *                          duplex       = NULL;
+    gs_free char *                        hwaddr       = NULL;
+    gs_free char *                        local_hwaddr = NULL;
+    gs_free char *                        hostname     = NULL;
+    guint32                               speed        = 0;
+    int                                   prefix       = -1;
+    NMSettingIPConfig *                   s_ip         = NULL;
+    NMSetting *                           s_ip4        = NULL;
+    NMSetting *                           s_ip6        = NULL;
+    NMSetting *                           s_wired      = NULL;
+    int                                   family       = AF_UNSPEC;
+    int                                   i            = 0;
+    char *                                c;
+    gs_free_error GError *error = NULL;
+
+    base = g_build_filename(sysfs_dir, "firmware", "devicetree", "base", NULL);
+
+    if (!dt_get_property(base, "chosen", "bootpath", &bootpath, NULL))
+        return NULL;
+
+    c = strchr(bootpath, ':');
+    if (c) {
+        *c   = '\0';
+        path = c + 1;
+    } else {
+        path = "";
+    }
+
+    dt_get_property(base, "chosen", "client-name", &hostname, NULL);
+
+    local_hwaddr = dt_get_hwaddr_property(base, bootpath, "local-mac-address");
+    hwaddr       = dt_get_hwaddr_property(base, bootpath, "mac-address");
+    if (nm_streq0(local_hwaddr, hwaddr))
+        nm_clear_g_free(&local_hwaddr);
+
+    tokens = g_strsplit(path, ",", 0);
+
+    /*
+     * Ethernet device settings. Defined by "Open Firmware,
+     * Recommended Practice: Device Support Extensions, Version 1.0 [1]
+     * [1] https://www.devicetree.org/open-firmware/practice/devicex/dse1_0a.ps
+     */
+
+    for (i = 0; tokens[i]; i++) {
+        /* Skip these. They have magical meaning for OpenFirmware. */
+        if (NM_IN_STRSET(tokens[i], "nfs", "last"))
+            continue;
+        if (nm_streq(tokens[i], "promiscuous")) {
+            /* Ignore. */
+            continue;
+        }
+
+        if (g_str_has_prefix(tokens[i], "speed=")) {
+            speed = _nm_utils_ascii_str_to_int64(tokens[i] + 6, 10, 0, G_MAXUINT32, 0);
+            continue;
+        }
+
+        if (g_str_has_prefix(tokens[i], "duplex=auto")) {
+            continue;
+        } else if (g_str_has_prefix(tokens[i], "duplex=half")
+                   || g_str_has_prefix(tokens[i], "duplex=full")) {
+            duplex = tokens[i] + 7;
+            continue;
+        }
+
+        break;
+    }
+
+    /*
+     * Network boot configuration. Defined by "Open Firmware,
+     * Recommended Practice: TFTP Booting Extension, Version 1.0 [1]
+     * [1] https://www.devicetree.org/open-firmware/practice/obp-tftp/tftp1_0.pdf
+     */
+
+    for (; tokens[i]; i++) {
+        if (NM_IN_STRSET(tokens[i], "bootp", "dhcp", "rarp")) {
+            bootp = TRUE;
+            continue;
+        }
+        break;
+    }
+
+    /* s-iaddr, or perhaps a raw absolute filename */
+    if (tokens[i] && tokens[i][0] != '/')
+        i++;
+
+    /* filename */
+    if (tokens[i])
+        i++;
+
+    /* c-iaddr */
+    if (tokens[i]) {
+        s_ipaddr = tokens[i];
+        i++;
+    }
+
+    /* g-iaddr */
+    if (tokens[i]) {
+        s_gateway = tokens[i];
+        i++;
+    }
+
+    if (tokens[i] && (strchr(tokens[i], '.') || strchr(tokens[i], ':'))) {
+        /* yaboot claims the mask can be specified here,
+         * though it doesn't support it. */
+        s_netmask = tokens[i];
+        i++;
+    }
+
+    /* bootp-retries */
+    if (tokens[i])
+        i++;
+
+    /* tftp-retries */
+    if (tokens[i])
+        i++;
+
+    if (tokens[i]) {
+        /* yaboot accepts a mask here */
+        s_netmask = tokens[i];
+        i++;
+    }
+
+    connection = nm_simple_connection_new();
+
+    nm_connection_add_setting(connection,
+                              g_object_new(NM_TYPE_SETTING_CONNECTION,
+                                           NM_SETTING_CONNECTION_TYPE,
+                                           NM_SETTING_WIRED_SETTING_NAME,
+                                           NM_SETTING_CONNECTION_ID,
+                                           "OpenFirmware Connection",
+                                           NULL));
+
+    s_ip4 = nm_setting_ip4_config_new();
+    nm_connection_add_setting(connection, s_ip4);
+
+    s_ip6 = nm_setting_ip6_config_new();
+    nm_connection_add_setting(connection, s_ip6);
+
+    g_object_set(s_ip6,
+                 NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE,
+                 (int) NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64,
+                 NULL);
+
+    if (!bootp && dt_get_property(base, "chosen", "bootp-response", NULL, NULL))
+        bootp = TRUE;
+
+    if (!bootp) {
+        nm_auto_unref_ip_address NMIPAddress *netmask = NULL;
+
+        netmask = dt_get_ipaddr_property(base, "chosen", "netmask-ip", &family);
+        gateway = dt_get_ipaddr_property(base, "chosen", "gateway-ip", &family);
+        if (gateway)
+            s_gateway = nm_ip_address_get_address(gateway);
+        ipaddr = dt_get_ipaddr_property(base, "chosen", "client-ip", &family);
+
+        if (family == AF_UNSPEC) {
+            nm_assert(netmask == NULL);
+            nm_assert(gateway == NULL);
+            nm_assert(ipaddr == NULL);
+
+            netmask = str_addr(s_netmask, &family);
+            ipaddr  = str_addr(s_ipaddr, &family);
+
+            prefix = _nm_utils_ascii_str_to_int64(s_netmask, 10, 0, 128, -1);
+        }
+
+        if (prefix == -1 && family == AF_INET && netmask) {
+            guint32 netmask_v4;
+
+            nm_ip_address_get_address_binary(netmask, &netmask_v4);
+            prefix = nm_utils_ip4_netmask_to_prefix(netmask_v4);
+        }
+
+        if (prefix == -1)
+            _LOGW(LOGD_CORE, "Unable to determine the network prefix");
+        else
+            nm_ip_address_set_prefix(ipaddr, prefix);
+    }
+
+    if (!ipaddr) {
+        family = AF_UNSPEC;
+        bootp  = TRUE;
+    }
+
+    if (bootp) {
+        g_object_set(s_ip4,
+                     NM_SETTING_IP_CONFIG_METHOD,
+                     NM_SETTING_IP4_CONFIG_METHOD_AUTO,
+                     NM_SETTING_IP_CONFIG_DHCP_HOSTNAME,
+                     hostname,
+                     NULL);
+        g_object_set(s_ip6,
+                     NM_SETTING_IP_CONFIG_METHOD,
+                     NM_SETTING_IP6_CONFIG_METHOD_AUTO,
+                     NM_SETTING_IP_CONFIG_DHCP_HOSTNAME,
+                     hostname,
+                     NULL);
+    } else {
+        switch (family) {
+        case AF_INET:
+            s_ip = (NMSettingIPConfig *) s_ip4;
+            g_object_set(s_ip4,
+                         NM_SETTING_IP_CONFIG_METHOD,
+                         NM_SETTING_IP4_CONFIG_METHOD_MANUAL,
+                         NULL);
+            g_object_set(s_ip6,
+                         NM_SETTING_IP_CONFIG_METHOD,
+                         NM_SETTING_IP6_CONFIG_METHOD_DISABLED,
+                         NULL);
+            break;
+        case AF_INET6:
+            s_ip = (NMSettingIPConfig *) s_ip6;
+            g_object_set(s_ip4,
+                         NM_SETTING_IP_CONFIG_METHOD,
+                         NM_SETTING_IP4_CONFIG_METHOD_DISABLED,
+                         NULL);
+            g_object_set(s_ip6,
+                         NM_SETTING_IP_CONFIG_METHOD,
+                         NM_SETTING_IP6_CONFIG_METHOD_MANUAL,
+                         NULL);
+            break;
+        default:
+            g_return_val_if_reached(NULL);
+        }
+
+        nm_setting_ip_config_add_address(s_ip, ipaddr);
+        g_object_set(s_ip, NM_SETTING_IP_CONFIG_GATEWAY, s_gateway, NULL);
+    }
+
+    if (duplex || speed || hwaddr || local_hwaddr) {
+        s_wired = nm_setting_wired_new();
+        nm_connection_add_setting(connection, s_wired);
+
+        g_object_set(s_wired,
+                     NM_SETTING_WIRED_SPEED,
+                     speed,
+                     NM_SETTING_WIRED_DUPLEX,
+                     duplex,
+                     NM_SETTING_WIRED_MAC_ADDRESS,
+                     hwaddr,
+                     NM_SETTING_WIRED_CLONED_MAC_ADDRESS,
+                     local_hwaddr,
+                     NULL);
+    }
+
+    if (!nm_connection_normalize(connection, NULL, NULL, &error)) {
+        _LOGW(LOGD_CORE, "Generated an invalid connection: %s", error->message);
+        nm_clear_pointer(&connection, g_object_unref);
+    }
+
+    return g_steal_pointer(&connection);
+}
diff --git a/src/nm-initrd-generator/nmi-ibft-reader.c b/src/nm-initrd-generator/nmi-ibft-reader.c
new file mode 100644
index 00000000..b3db3f01
--- /dev/null
+++ b/src/nm-initrd-generator/nmi-ibft-reader.c
@@ -0,0 +1,465 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2014 - 2018 Red Hat, Inc.
+ */
+
+#include "libnm-core-impl/nm-default-libnm-core.h"
+
+#include "nm-initrd-generator.h"
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <sys/wait.h>
+#include <sys/inotify.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <linux/if_ether.h>
+
+#include "libnm-glib-aux/nm-uuid.h"
+#include "libnm-log-core/nm-logging.h"
+#include "libnm-core-intern/nm-core-internal.h"
+#include "libnm-platform/nm-platform-utils.h"
+
+/*****************************************************************************/
+
+#define _NMLOG(level, domain, ...) \
+    nm_log((level),                \
+           (domain),               \
+           NULL,                   \
+           NULL,                   \
+           "ibft-reader: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__) _NM_UTILS_MACRO_REST(__VA_ARGS__))
+
+/*****************************************************************************/
+
+static GHashTable *
+load_one_nic(const char *sysfs_dir, const char *dir_name)
+{
+    gs_free char *nic_path = g_build_filename(sysfs_dir, dir_name, NULL);
+    GDir *        nic_dir;
+    const char *  entry_name;
+    char *        content;
+    gs_free_error GError *error = NULL;
+    GHashTable *          nic;
+
+    g_return_val_if_fail(sysfs_dir != NULL, FALSE);
+
+    nic_dir = g_dir_open(nic_path, 0, &error);
+    if (!nic_dir) {
+        _LOGW(LOGD_CORE, "Can't open %s: %s", nic_path, error->message);
+        return NULL;
+    }
+
+    nic = g_hash_table_new_full(nm_str_hash, g_str_equal, g_free, g_free);
+    while ((entry_name = g_dir_read_name(nic_dir))) {
+        gs_free char *entry_path = g_build_filename(nic_path, entry_name, NULL);
+
+        if (!g_file_test(entry_path, G_FILE_TEST_IS_REGULAR))
+            continue;
+
+        if (!g_file_get_contents(entry_path, &content, NULL, &error)) {
+            _LOGW(LOGD_CORE, "Can't read %s: %s", entry_path, error->message);
+            g_clear_error(&error);
+            continue;
+        }
+
+        g_strchomp(content);
+        if (!g_hash_table_insert(nic, g_strdup(entry_name), content))
+            _LOGW(LOGD_CORE, "Duplicate iBFT entry: %s", entry_name);
+    }
+
+    g_dir_close(nic_dir);
+
+    return nic;
+}
+
+GHashTable *
+nmi_ibft_read(const char *sysfs_dir)
+{
+    gs_free char *ibft_path = NULL;
+    GDir *        ibft_dir;
+    const char *  dir_name;
+    GHashTable *  ibft, *nic;
+    char *        mac;
+    gs_free_error GError *error = NULL;
+
+    g_return_val_if_fail(sysfs_dir != NULL, FALSE);
+
+    ibft_path = g_build_filename(sysfs_dir, "firmware", "ibft", NULL);
+
+    ibft = g_hash_table_new_full(nm_str_hash,
+                                 g_str_equal,
+                                 g_free,
+                                 (GDestroyNotify) g_hash_table_unref);
+
+    if (!g_file_test(ibft_path, G_FILE_TEST_IS_DIR))
+        nmp_utils_modprobe(NULL, FALSE, "iscsi_ibft", NULL);
+    if (!g_file_test(ibft_path, G_FILE_TEST_IS_DIR))
+        return ibft;
+
+    ibft_dir = g_dir_open(ibft_path, 0, &error);
+    if (!ibft_dir) {
+        _LOGW(LOGD_CORE, "Unable to open iBFT firmware directory: %s", error->message);
+        return ibft;
+    }
+
+    while ((dir_name = g_dir_read_name(ibft_dir))) {
+        if (!g_str_has_prefix(dir_name, "ethernet"))
+            continue;
+
+        nic = load_one_nic(ibft_path, dir_name);
+        mac = g_hash_table_lookup(nic, "mac");
+
+        if (!mac) {
+            _LOGW(LOGD_CORE, "Ignoring an iBFT record without a MAC address");
+            g_hash_table_unref(nic);
+            continue;
+        }
+
+        mac = g_ascii_strup(mac, -1);
+        if (!g_hash_table_insert(ibft, mac, nic))
+            _LOGW(LOGD_CORE, "Duplicate iBFT record for %s", mac);
+    }
+
+    g_dir_close(ibft_dir);
+
+    return ibft;
+}
+
+static gboolean
+ip_setting_add_from_block(GHashTable *nic, NMConnection *connection, GError **error)
+{
+    NMSettingIPConfig *s_ip  = NULL;
+    NMSettingIPConfig *s_ip4 = NULL;
+    NMSettingIPConfig *s_ip6 = NULL;
+    NMIPAddress *      addr;
+    const char *       s_ipaddr  = NULL;
+    const char *       s_prefix  = NULL;
+    const char *       s_gateway = NULL;
+    const char *       s_dns1    = NULL;
+    const char *       s_dns2    = NULL;
+    const char *       s_origin  = NULL;
+    const char *       method    = NULL;
+    int                family;
+    gint64             prefix;
+
+    s_ipaddr  = (const char *) g_hash_table_lookup(nic, "ip-addr");
+    s_prefix  = (const char *) g_hash_table_lookup(nic, "prefix-len");
+    s_gateway = (const char *) g_hash_table_lookup(nic, "gateway");
+    s_dns1    = (const char *) g_hash_table_lookup(nic, "primary-dns");
+    s_dns2    = (const char *) g_hash_table_lookup(nic, "secondary-dns");
+    s_origin  = (const char *) g_hash_table_lookup(nic, "origin");
+
+    s_ip4 = nm_connection_get_setting_ip4_config(connection);
+    if (!s_ip4) {
+        s_ip4 = (NMSettingIPConfig *) nm_setting_ip4_config_new();
+        nm_connection_add_setting(connection, (NMSetting *) s_ip4);
+    }
+
+    s_ip6 = nm_connection_get_setting_ip6_config(connection);
+    if (!s_ip6) {
+        s_ip6 = (NMSettingIPConfig *) nm_setting_ip6_config_new();
+        nm_connection_add_setting(connection, (NMSetting *) s_ip6);
+
+        g_object_set(s_ip6,
+                     NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE,
+                     (int) NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64,
+                     NULL);
+    }
+
+    family = get_ip_address_family(s_ipaddr, FALSE);
+    if (family == AF_UNSPEC)
+        family = get_ip_address_family(s_gateway, FALSE);
+
+    switch (family) {
+    case AF_INET:
+        s_ip = s_ip4;
+        g_object_set(s_ip6,
+                     NM_SETTING_IP_CONFIG_METHOD,
+                     NM_SETTING_IP6_CONFIG_METHOD_DISABLED,
+                     NULL);
+        break;
+    case AF_INET6:
+        s_ip = s_ip6;
+        g_object_set(s_ip4,
+                     NM_SETTING_IP_CONFIG_METHOD,
+                     NM_SETTING_IP4_CONFIG_METHOD_DISABLED,
+                     NULL);
+        break;
+    default:
+        g_set_error(error,
+                    NM_SETTINGS_ERROR,
+                    NM_SETTINGS_ERROR_INVALID_CONNECTION,
+                    "iBFT: invalid IP address '%s'.",
+                    s_ipaddr);
+        return FALSE;
+    }
+
+    if ((nm_streq0(s_origin, "3") && family == AF_INET)
+        || (nm_streq0(s_origin, "4") && family == AF_INET)) {
+        method = NM_SETTING_IP4_CONFIG_METHOD_AUTO;
+    } else if (nm_streq0(s_origin, "3") && family == AF_INET6) {
+        method = NM_SETTING_IP6_CONFIG_METHOD_DHCP;
+    } else if (nm_streq0(s_origin, "4") && family == AF_INET6) {
+        method = NM_SETTING_IP6_CONFIG_METHOD_AUTO;
+    } else if (family == AF_INET) {
+        method = NM_SETTING_IP4_CONFIG_METHOD_MANUAL;
+    } else if (family == AF_INET6) {
+        method = NM_SETTING_IP6_CONFIG_METHOD_MANUAL;
+    } else {
+        g_return_val_if_reached(FALSE);
+    }
+    g_object_set(s_ip,
+                 NM_SETTING_IP_CONFIG_METHOD,
+                 method,
+                 NM_SETTING_IP_CONFIG_MAY_FAIL,
+                 FALSE,
+                 NULL);
+
+    if (s_gateway && !nm_utils_ipaddr_is_valid(family, s_gateway)) {
+        g_set_error(error,
+                    NM_SETTINGS_ERROR,
+                    NM_SETTINGS_ERROR_INVALID_CONNECTION,
+                    "iBFT: invalid IP gateway '%s'.",
+                    s_gateway);
+        return FALSE;
+    }
+
+    if (s_dns1 && !nm_utils_ipaddr_is_valid(family, s_dns1)) {
+        g_set_error(error,
+                    NM_SETTINGS_ERROR,
+                    NM_SETTINGS_ERROR_INVALID_CONNECTION,
+                    "iBFT: invalid DNS1 address '%s'.",
+                    s_dns1);
+        return FALSE;
+    }
+
+    if (s_dns2 && !nm_utils_ipaddr_is_valid(family, s_dns2)) {
+        g_set_error(error,
+                    NM_SETTINGS_ERROR,
+                    NM_SETTINGS_ERROR_INVALID_CONNECTION,
+                    "iBFT: invalid DNS2 address '%s'.",
+                    s_dns2);
+        return FALSE;
+    }
+
+    if (s_ipaddr) {
+        prefix = _nm_utils_ascii_str_to_int64(s_prefix, 10, 0, 128, -1);
+        if (prefix == -1) {
+            g_set_error(error,
+                        NM_SETTINGS_ERROR,
+                        NM_SETTINGS_ERROR_INVALID_CONNECTION,
+                        "iBFT: invalid IP prefix '%s'.",
+                        s_prefix);
+            return FALSE;
+        }
+
+        addr = nm_ip_address_new(family, s_ipaddr, prefix, error);
+        if (!addr) {
+            g_prefix_error(error, "iBFT: ");
+            return FALSE;
+        }
+
+        nm_setting_ip_config_add_address(s_ip, addr);
+        nm_ip_address_unref(addr);
+
+        g_object_set(s_ip, NM_SETTING_IP_CONFIG_GATEWAY, s_gateway, NULL);
+    }
+
+    if (s_dns1)
+        nm_setting_ip_config_add_dns(s_ip, s_dns1);
+    if (s_dns2)
+        nm_setting_ip_config_add_dns(s_ip, s_dns2);
+
+    return TRUE;
+}
+
+static gboolean
+connection_setting_add(GHashTable *  nic,
+                       NMConnection *connection,
+                       const char *  type,
+                       const char *  prefix,
+                       GError **     error)
+{
+    NMSetting * s_con;
+    char *      id, *uuid;
+    const char *s_index, *s_hwaddr, *s_ipaddr, *s_vlanid;
+
+    s_index  = (const char *) g_hash_table_lookup(nic, "index");
+    s_hwaddr = (const char *) g_hash_table_lookup(nic, "mac");
+    s_ipaddr = (const char *) g_hash_table_lookup(nic, "ip-addr");
+    s_vlanid = (const char *) g_hash_table_lookup(nic, "vlan");
+
+    if (!s_hwaddr) {
+        g_set_error_literal(error,
+                            NM_SETTINGS_ERROR,
+                            NM_SETTINGS_ERROR_INVALID_CONNECTION,
+                            "iBFT: missing MAC address");
+        return FALSE;
+    }
+
+    id = g_strdup_printf("iBFT%s%s Connection%s%s",
+                         prefix ? " " : "",
+                         prefix ? prefix : "",
+                         s_index ? " " : "",
+                         s_index ? s_index : "");
+
+    uuid = nm_uuid_generate_from_strings("ibft",
+                                         s_hwaddr,
+                                         s_vlanid ? "V" : "v",
+                                         s_vlanid ? s_vlanid : "",
+                                         s_ipaddr ? "A" : "DHCP",
+                                         s_ipaddr ? s_ipaddr : "",
+                                         NULL);
+
+    s_con = (NMSetting *) nm_connection_get_setting_connection(connection);
+    if (!s_con) {
+        s_con = nm_setting_connection_new();
+        nm_connection_add_setting(connection, s_con);
+    }
+
+    g_object_set(s_con,
+                 NM_SETTING_CONNECTION_TYPE,
+                 type,
+                 NM_SETTING_CONNECTION_UUID,
+                 uuid,
+                 NM_SETTING_CONNECTION_ID,
+                 id,
+                 NM_SETTING_CONNECTION_INTERFACE_NAME,
+                 NULL,
+                 NULL);
+
+    g_free(uuid);
+    g_free(id);
+
+    return TRUE;
+}
+
+static gboolean
+is_ibft_vlan_device(GHashTable *nic)
+{
+    const char *s_vlan_id;
+
+    g_assert(nic);
+
+    s_vlan_id = (const char *) g_hash_table_lookup(nic, "vlan");
+
+    if (s_vlan_id) {
+        /* VLAN 0 is normally a valid VLAN ID, but in the iBFT case it
+         * means "no VLAN".
+         */
+        if (_nm_utils_ascii_str_to_int64(s_vlan_id, 10, 1, 4095, -1) != -1)
+            return TRUE;
+    }
+
+    return FALSE;
+}
+
+static gboolean
+vlan_setting_add_from_block(GHashTable *nic, NMConnection *connection, GError **error)
+{
+    NMSetting * s_vlan      = NULL;
+    const char *vlan_id_str = NULL;
+    gint64      vlan_id     = -1;
+
+    g_assert(nic);
+    g_assert(connection);
+
+    /* This won't fail since this function shouldn't be called unless the
+     * iBFT VLAN ID exists and is > 0.
+     */
+    vlan_id_str = (const char *) g_hash_table_lookup(nic, "vlan");
+    g_assert(vlan_id_str);
+
+    /* VLAN 0 is normally a valid VLAN ID, but in the iBFT case it means "no VLAN" */
+    vlan_id = _nm_utils_ascii_str_to_int64(vlan_id_str, 10, 1, 4095, -1);
+    if (vlan_id == -1) {
+        g_set_error(error,
+                    NM_SETTINGS_ERROR,
+                    NM_SETTINGS_ERROR_INVALID_CONNECTION,
+                    "Invalid VLAN_ID '%s'",
+                    vlan_id_str);
+        return FALSE;
+    }
+
+    s_vlan = (NMSetting *) nm_connection_get_setting_vlan(connection);
+    if (!s_vlan) {
+        s_vlan = nm_setting_vlan_new();
+        nm_connection_add_setting(connection, s_vlan);
+    }
+
+    g_object_set(s_vlan, NM_SETTING_VLAN_ID, (guint32) vlan_id, NULL);
+
+    return TRUE;
+}
+
+static gboolean
+wired_setting_add_from_block(GHashTable *nic, NMConnection *connection, GError **error)
+{
+    NMSetting * s_wired = NULL;
+    const char *hwaddr  = NULL;
+
+    g_assert(nic);
+    g_assert(connection);
+
+    hwaddr = (const char *) g_hash_table_lookup(nic, "mac");
+    if (!hwaddr) {
+        g_set_error_literal(error,
+                            NM_SETTINGS_ERROR,
+                            NM_SETTINGS_ERROR_INVALID_CONNECTION,
+                            "iBFT: missing MAC address");
+        return FALSE;
+    }
+
+    if (!nm_utils_hwaddr_valid(hwaddr, ETH_ALEN)) {
+        g_set_error(error,
+                    NM_SETTINGS_ERROR,
+                    NM_SETTINGS_ERROR_INVALID_CONNECTION,
+                    "iBFT: invalid MAC address '%s'.",
+                    hwaddr);
+        return FALSE;
+    }
+
+    s_wired = (NMSetting *) nm_connection_get_setting_wired(connection);
+    if (!s_wired) {
+        s_wired = nm_setting_wired_new();
+        nm_connection_add_setting(connection, s_wired);
+    }
+
+    g_object_set(s_wired, NM_SETTING_WIRED_MAC_ADDRESS, hwaddr, NULL);
+
+    return TRUE;
+}
+
+gboolean
+nmi_ibft_update_connection_from_nic(NMConnection *connection, GHashTable *nic, GError **error)
+{
+    gboolean is_vlan = FALSE;
+
+    g_assert(nic);
+
+    is_vlan = is_ibft_vlan_device(nic);
+    if (is_vlan && !vlan_setting_add_from_block(nic, connection, error))
+        return FALSE;
+
+    /* Always have a wired setting; for VLAN it defines the parent */
+    if (!wired_setting_add_from_block(nic, connection, error))
+        return FALSE;
+
+    if (!ip_setting_add_from_block(nic, connection, error))
+        return FALSE;
+
+    if (!connection_setting_add(nic,
+                                connection,
+                                is_vlan ? NM_SETTING_VLAN_SETTING_NAME
+                                        : NM_SETTING_WIRED_SETTING_NAME,
+                                is_vlan ? "VLAN" : NULL,
+                                error))
+        return FALSE;
+
+    if (!nm_connection_normalize(connection, NULL, NULL, error))
+        return FALSE;
+
+    return TRUE;
+}
diff --git a/src/nm-initrd-generator/tests/meson.build b/src/nm-initrd-generator/tests/meson.build
new file mode 100644
index 00000000..8fa3bcac
--- /dev/null
+++ b/src/nm-initrd-generator/tests/meson.build
@@ -0,0 +1,43 @@
+# SPDX-License-Identifier: LGPL-2.1-or-later
+
+test_units = [
+  'test-dt-reader',
+  'test-ibft-reader',
+  'test-cmdline-reader',
+]
+
+foreach test_unit : test_units
+  exe = executable(
+    test_unit,
+    test_unit + '.c',
+    include_directories: [
+      src_inc,
+      top_inc,
+    ],
+    dependencies: [
+      libnm_core_public_dep,
+    ],
+    c_args: test_c_flags,
+    link_with: [
+      libnmi_core,
+      libnm_core_aux_intern,
+      libnm_core_impl,
+      libnm_crypto,
+      libnm_platform,
+      libnm_base,
+      libnm_systemd_shared,
+      libnm_udev_aux,
+      libnm_log_core,
+      libnm_glib_aux,
+      libnm_std_aux,
+      libc_siphash,
+    ],
+  )
+
+  test(
+    'nm-initrd-generator/tests/' + test_unit,
+    test_script,
+    timeout: default_test_timeout,
+    args: test_args + [exe.full_path()],
+  )
+endforeach
diff --git a/src/nm-initrd-generator/tests/sysfs-bad-dns1/class/net/eth0/address b/src/nm-initrd-generator/tests/sysfs-bad-dns1/class/net/eth0/address
new file mode 100644
index 00000000..20659db7
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-bad-dns1/class/net/eth0/address
@@ -0,0 +1 @@
+00:33:21:98:b9:f0
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/gateway b/src/nm-initrd-generator/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/gateway
new file mode 100644
index 00000000..bf6cf454
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/gateway
@@ -0,0 +1 @@
+192.168.35.254
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/index b/src/nm-initrd-generator/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/index
new file mode 100644
index 00000000..c2270834
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/index
@@ -0,0 +1 @@
+0
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/ip-addr b/src/nm-initrd-generator/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/ip-addr
new file mode 100644
index 00000000..944c8d45
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/ip-addr
@@ -0,0 +1 @@
+192.168.32.72
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/mac b/src/nm-initrd-generator/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/mac
new file mode 100644
index 00000000..20659db7
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/mac
@@ -0,0 +1 @@
+00:33:21:98:b9:f0
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/origin b/src/nm-initrd-generator/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/origin
new file mode 100644
index 00000000..56a6051c
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/origin
@@ -0,0 +1 @@
+1
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/prefix-len b/src/nm-initrd-generator/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/prefix-len
new file mode 100644
index 00000000..8fdd954d
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/prefix-len
@@ -0,0 +1 @@
+22
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/primary-dns b/src/nm-initrd-generator/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/primary-dns
new file mode 100644
index 00000000..2303dbdc
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/primary-dns
@@ -0,0 +1 @@
+10000.500.250.1
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/secondary-dns b/src/nm-initrd-generator/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/secondary-dns
new file mode 100644
index 00000000..2eb9e1d0
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/secondary-dns
@@ -0,0 +1 @@
+10.16.255.3
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/subnet-mask b/src/nm-initrd-generator/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/subnet-mask
new file mode 100644
index 00000000..7cb9d0a9
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/subnet-mask
@@ -0,0 +1 @@
+255.255.252.0
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/vlan b/src/nm-initrd-generator/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/vlan
new file mode 100644
index 00000000..c2270834
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/vlan
@@ -0,0 +1 @@
+0
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-bad-dns1/firmware/ibft/initiator/initiator-name b/src/nm-initrd-generator/tests/sysfs-bad-dns1/firmware/ibft/initiator/initiator-name
new file mode 100644
index 00000000..509a7ab8
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-bad-dns1/firmware/ibft/initiator/initiator-name
@@ -0,0 +1 @@
+iqn.pjones6
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-bad-dns1/firmware/ibft/target0/index b/src/nm-initrd-generator/tests/sysfs-bad-dns1/firmware/ibft/target0/index
new file mode 100644
index 00000000..c2270834
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-bad-dns1/firmware/ibft/target0/index
@@ -0,0 +1 @@
+0
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-bad-dns1/firmware/ibft/target0/ip-addr b/src/nm-initrd-generator/tests/sysfs-bad-dns1/firmware/ibft/target0/ip-addr
new file mode 100644
index 00000000..7450fdf9
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-bad-dns1/firmware/ibft/target0/ip-addr
@@ -0,0 +1 @@
+10.16.52.16
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-bad-dns1/firmware/ibft/target0/lun b/src/nm-initrd-generator/tests/sysfs-bad-dns1/firmware/ibft/target0/lun
new file mode 100644
index 00000000..c43d0930
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-bad-dns1/firmware/ibft/target0/lun
@@ -0,0 +1 @@
+00000000
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-bad-dns1/firmware/ibft/target0/port b/src/nm-initrd-generator/tests/sysfs-bad-dns1/firmware/ibft/target0/port
new file mode 100644
index 00000000..58f0d919
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-bad-dns1/firmware/ibft/target0/port
@@ -0,0 +1 @@
+3260
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-bad-dns1/firmware/ibft/target0/target-name b/src/nm-initrd-generator/tests/sysfs-bad-dns1/firmware/ibft/target0/target-name
new file mode 100644
index 00000000..32c9450a
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-bad-dns1/firmware/ibft/target0/target-name
@@ -0,0 +1 @@
+iqn.0.2008-11.com.blahblah:iscsi0
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-bad-dns2/class/net/eth0/address b/src/nm-initrd-generator/tests/sysfs-bad-dns2/class/net/eth0/address
new file mode 100644
index 00000000..20659db7
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-bad-dns2/class/net/eth0/address
@@ -0,0 +1 @@
+00:33:21:98:b9:f0
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/gateway b/src/nm-initrd-generator/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/gateway
new file mode 100644
index 00000000..bf6cf454
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/gateway
@@ -0,0 +1 @@
+192.168.35.254
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/index b/src/nm-initrd-generator/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/index
new file mode 100644
index 00000000..c2270834
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/index
@@ -0,0 +1 @@
+0
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/ip-addr b/src/nm-initrd-generator/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/ip-addr
new file mode 100644
index 00000000..944c8d45
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/ip-addr
@@ -0,0 +1 @@
+192.168.32.72
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/mac b/src/nm-initrd-generator/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/mac
new file mode 100644
index 00000000..20659db7
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/mac
@@ -0,0 +1 @@
+00:33:21:98:b9:f0
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/origin b/src/nm-initrd-generator/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/origin
new file mode 100644
index 00000000..56a6051c
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/origin
@@ -0,0 +1 @@
+1
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/prefix-len b/src/nm-initrd-generator/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/prefix-len
new file mode 100644
index 00000000..8fdd954d
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/prefix-len
@@ -0,0 +1 @@
+22
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/primary-dns b/src/nm-initrd-generator/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/primary-dns
new file mode 100644
index 00000000..2e152cb0
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/primary-dns
@@ -0,0 +1 @@
+10.16.255.2
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/secondary-dns b/src/nm-initrd-generator/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/secondary-dns
new file mode 100644
index 00000000..5ed7b719
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/secondary-dns
@@ -0,0 +1 @@
+blah.foo.bar.baz
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/subnet-mask b/src/nm-initrd-generator/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/subnet-mask
new file mode 100644
index 00000000..7cb9d0a9
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/subnet-mask
@@ -0,0 +1 @@
+255.255.252.0
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/vlan b/src/nm-initrd-generator/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/vlan
new file mode 100644
index 00000000..c2270834
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/vlan
@@ -0,0 +1 @@
+0
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-bad-dns2/firmware/ibft/initiator/initiator-name b/src/nm-initrd-generator/tests/sysfs-bad-dns2/firmware/ibft/initiator/initiator-name
new file mode 100644
index 00000000..509a7ab8
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-bad-dns2/firmware/ibft/initiator/initiator-name
@@ -0,0 +1 @@
+iqn.pjones6
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-bad-dns2/firmware/ibft/target0/index b/src/nm-initrd-generator/tests/sysfs-bad-dns2/firmware/ibft/target0/index
new file mode 100644
index 00000000..c2270834
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-bad-dns2/firmware/ibft/target0/index
@@ -0,0 +1 @@
+0
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-bad-dns2/firmware/ibft/target0/ip-addr b/src/nm-initrd-generator/tests/sysfs-bad-dns2/firmware/ibft/target0/ip-addr
new file mode 100644
index 00000000..7450fdf9
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-bad-dns2/firmware/ibft/target0/ip-addr
@@ -0,0 +1 @@
+10.16.52.16
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-bad-dns2/firmware/ibft/target0/lun b/src/nm-initrd-generator/tests/sysfs-bad-dns2/firmware/ibft/target0/lun
new file mode 100644
index 00000000..c43d0930
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-bad-dns2/firmware/ibft/target0/lun
@@ -0,0 +1 @@
+00000000
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-bad-dns2/firmware/ibft/target0/port b/src/nm-initrd-generator/tests/sysfs-bad-dns2/firmware/ibft/target0/port
new file mode 100644
index 00000000..58f0d919
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-bad-dns2/firmware/ibft/target0/port
@@ -0,0 +1 @@
+3260
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-bad-dns2/firmware/ibft/target0/target-name b/src/nm-initrd-generator/tests/sysfs-bad-dns2/firmware/ibft/target0/target-name
new file mode 100644
index 00000000..32c9450a
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-bad-dns2/firmware/ibft/target0/target-name
@@ -0,0 +1 @@
+iqn.0.2008-11.com.blahblah:iscsi0
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-bad-gateway/class/net/eth0/address b/src/nm-initrd-generator/tests/sysfs-bad-gateway/class/net/eth0/address
new file mode 100644
index 00000000..20659db7
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-bad-gateway/class/net/eth0/address
@@ -0,0 +1 @@
+00:33:21:98:b9:f0
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/gateway b/src/nm-initrd-generator/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/gateway
new file mode 100644
index 00000000..1970856e
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/gateway
@@ -0,0 +1 @@
+bb.cc.dd.ee
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/index b/src/nm-initrd-generator/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/index
new file mode 100644
index 00000000..c2270834
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/index
@@ -0,0 +1 @@
+0
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/ip-addr b/src/nm-initrd-generator/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/ip-addr
new file mode 100644
index 00000000..944c8d45
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/ip-addr
@@ -0,0 +1 @@
+192.168.32.72
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/mac b/src/nm-initrd-generator/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/mac
new file mode 100644
index 00000000..20659db7
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/mac
@@ -0,0 +1 @@
+00:33:21:98:b9:f0
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/origin b/src/nm-initrd-generator/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/origin
new file mode 100644
index 00000000..56a6051c
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/origin
@@ -0,0 +1 @@
+1
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/prefix-len b/src/nm-initrd-generator/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/prefix-len
new file mode 100644
index 00000000..8fdd954d
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/prefix-len
@@ -0,0 +1 @@
+22
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/primary-dns b/src/nm-initrd-generator/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/primary-dns
new file mode 100644
index 00000000..2e152cb0
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/primary-dns
@@ -0,0 +1 @@
+10.16.255.2
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/secondary-dns b/src/nm-initrd-generator/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/secondary-dns
new file mode 100644
index 00000000..2eb9e1d0
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/secondary-dns
@@ -0,0 +1 @@
+10.16.255.3
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/subnet-mask b/src/nm-initrd-generator/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/subnet-mask
new file mode 100644
index 00000000..7cb9d0a9
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/subnet-mask
@@ -0,0 +1 @@
+255.255.252.0
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/vlan b/src/nm-initrd-generator/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/vlan
new file mode 100644
index 00000000..c2270834
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/vlan
@@ -0,0 +1 @@
+0
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-bad-gateway/firmware/ibft/initiator/initiator-name b/src/nm-initrd-generator/tests/sysfs-bad-gateway/firmware/ibft/initiator/initiator-name
new file mode 100644
index 00000000..509a7ab8
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-bad-gateway/firmware/ibft/initiator/initiator-name
@@ -0,0 +1 @@
+iqn.pjones6
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-bad-gateway/firmware/ibft/target0/index b/src/nm-initrd-generator/tests/sysfs-bad-gateway/firmware/ibft/target0/index
new file mode 100644
index 00000000..c2270834
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-bad-gateway/firmware/ibft/target0/index
@@ -0,0 +1 @@
+0
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-bad-gateway/firmware/ibft/target0/ip-addr b/src/nm-initrd-generator/tests/sysfs-bad-gateway/firmware/ibft/target0/ip-addr
new file mode 100644
index 00000000..7450fdf9
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-bad-gateway/firmware/ibft/target0/ip-addr
@@ -0,0 +1 @@
+10.16.52.16
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-bad-gateway/firmware/ibft/target0/lun b/src/nm-initrd-generator/tests/sysfs-bad-gateway/firmware/ibft/target0/lun
new file mode 100644
index 00000000..c43d0930
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-bad-gateway/firmware/ibft/target0/lun
@@ -0,0 +1 @@
+00000000
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-bad-gateway/firmware/ibft/target0/port b/src/nm-initrd-generator/tests/sysfs-bad-gateway/firmware/ibft/target0/port
new file mode 100644
index 00000000..58f0d919
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-bad-gateway/firmware/ibft/target0/port
@@ -0,0 +1 @@
+3260
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-bad-gateway/firmware/ibft/target0/target-name b/src/nm-initrd-generator/tests/sysfs-bad-gateway/firmware/ibft/target0/target-name
new file mode 100644
index 00000000..32c9450a
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-bad-gateway/firmware/ibft/target0/target-name
@@ -0,0 +1 @@
+iqn.0.2008-11.com.blahblah:iscsi0
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-bad-ipaddr/class/net/eth0/address b/src/nm-initrd-generator/tests/sysfs-bad-ipaddr/class/net/eth0/address
new file mode 100644
index 00000000..20659db7
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-bad-ipaddr/class/net/eth0/address
@@ -0,0 +1 @@
+00:33:21:98:b9:f0
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/gateway b/src/nm-initrd-generator/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/gateway
new file mode 100644
index 00000000..bf6cf454
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/gateway
@@ -0,0 +1 @@
+192.168.35.254
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/index b/src/nm-initrd-generator/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/index
new file mode 100644
index 00000000..c2270834
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/index
@@ -0,0 +1 @@
+0
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/ip-addr b/src/nm-initrd-generator/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/ip-addr
new file mode 100644
index 00000000..d526f324
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/ip-addr
@@ -0,0 +1 @@
+aa.bb.cc.dd
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/mac b/src/nm-initrd-generator/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/mac
new file mode 100644
index 00000000..20659db7
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/mac
@@ -0,0 +1 @@
+00:33:21:98:b9:f0
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/origin b/src/nm-initrd-generator/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/origin
new file mode 100644
index 00000000..56a6051c
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/origin
@@ -0,0 +1 @@
+1
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/prefix-len b/src/nm-initrd-generator/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/prefix-len
new file mode 100644
index 00000000..8fdd954d
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/prefix-len
@@ -0,0 +1 @@
+22
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/primary-dns b/src/nm-initrd-generator/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/primary-dns
new file mode 100644
index 00000000..2e152cb0
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/primary-dns
@@ -0,0 +1 @@
+10.16.255.2
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/secondary-dns b/src/nm-initrd-generator/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/secondary-dns
new file mode 100644
index 00000000..2eb9e1d0
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/secondary-dns
@@ -0,0 +1 @@
+10.16.255.3
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/subnet-mask b/src/nm-initrd-generator/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/subnet-mask
new file mode 100644
index 00000000..7cb9d0a9
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/subnet-mask
@@ -0,0 +1 @@
+255.255.252.0
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/vlan b/src/nm-initrd-generator/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/vlan
new file mode 100644
index 00000000..c2270834
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/vlan
@@ -0,0 +1 @@
+0
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-bad-ipaddr/firmware/ibft/initiator/initiator-name b/src/nm-initrd-generator/tests/sysfs-bad-ipaddr/firmware/ibft/initiator/initiator-name
new file mode 100644
index 00000000..509a7ab8
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-bad-ipaddr/firmware/ibft/initiator/initiator-name
@@ -0,0 +1 @@
+iqn.pjones6
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-bad-ipaddr/firmware/ibft/target0/index b/src/nm-initrd-generator/tests/sysfs-bad-ipaddr/firmware/ibft/target0/index
new file mode 100644
index 00000000..c2270834
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-bad-ipaddr/firmware/ibft/target0/index
@@ -0,0 +1 @@
+0
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-bad-ipaddr/firmware/ibft/target0/ip-addr b/src/nm-initrd-generator/tests/sysfs-bad-ipaddr/firmware/ibft/target0/ip-addr
new file mode 100644
index 00000000..7450fdf9
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-bad-ipaddr/firmware/ibft/target0/ip-addr
@@ -0,0 +1 @@
+10.16.52.16
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-bad-ipaddr/firmware/ibft/target0/lun b/src/nm-initrd-generator/tests/sysfs-bad-ipaddr/firmware/ibft/target0/lun
new file mode 100644
index 00000000..c43d0930
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-bad-ipaddr/firmware/ibft/target0/lun
@@ -0,0 +1 @@
+00000000
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-bad-ipaddr/firmware/ibft/target0/port b/src/nm-initrd-generator/tests/sysfs-bad-ipaddr/firmware/ibft/target0/port
new file mode 100644
index 00000000..58f0d919
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-bad-ipaddr/firmware/ibft/target0/port
@@ -0,0 +1 @@
+3260
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-bad-ipaddr/firmware/ibft/target0/target-name b/src/nm-initrd-generator/tests/sysfs-bad-ipaddr/firmware/ibft/target0/target-name
new file mode 100644
index 00000000..32c9450a
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-bad-ipaddr/firmware/ibft/target0/target-name
@@ -0,0 +1 @@
+iqn.0.2008-11.com.blahblah:iscsi0
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-dhcp/class/net/eth0/address b/src/nm-initrd-generator/tests/sysfs-dhcp/class/net/eth0/address
new file mode 100644
index 00000000..20659db7
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-dhcp/class/net/eth0/address
@@ -0,0 +1 @@
+00:33:21:98:b9:f0
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-dhcp/class/net/eth1/address b/src/nm-initrd-generator/tests/sysfs-dhcp/class/net/eth1/address
new file mode 100644
index 00000000..befa7850
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-dhcp/class/net/eth1/address
@@ -0,0 +1 @@
+00:33:21:98:b9:f1
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/ethernet0/gateway b/src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/ethernet0/gateway
new file mode 100644
index 00000000..59ea5b82
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/ethernet0/gateway
@@ -0,0 +1 @@
+10.16.52.254
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/ethernet0/index b/src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/ethernet0/index
new file mode 100644
index 00000000..c2270834
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/ethernet0/index
@@ -0,0 +1 @@
+0
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/ethernet0/mac b/src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/ethernet0/mac
new file mode 100644
index 00000000..20659db7
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/ethernet0/mac
@@ -0,0 +1 @@
+00:33:21:98:b9:f0
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/ethernet0/origin b/src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/ethernet0/origin
new file mode 100644
index 00000000..e440e5c8
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/ethernet0/origin
@@ -0,0 +1 @@
+3
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/ethernet0/primary-dns b/src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/ethernet0/primary-dns
new file mode 100644
index 00000000..2e152cb0
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/ethernet0/primary-dns
@@ -0,0 +1 @@
+10.16.255.2
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/ethernet0/secondary-dns b/src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/ethernet0/secondary-dns
new file mode 100644
index 00000000..2eb9e1d0
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/ethernet0/secondary-dns
@@ -0,0 +1 @@
+10.16.255.3
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/ethernet0/vlan b/src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/ethernet0/vlan
new file mode 100644
index 00000000..c2270834
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/ethernet0/vlan
@@ -0,0 +1 @@
+0
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/ethernet1/gateway b/src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/ethernet1/gateway
new file mode 100644
index 00000000..59ea5b82
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/ethernet1/gateway
@@ -0,0 +1 @@
+10.16.52.254
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/ethernet1/index b/src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/ethernet1/index
new file mode 100644
index 00000000..56a6051c
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/ethernet1/index
@@ -0,0 +1 @@
+1
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/ethernet1/mac b/src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/ethernet1/mac
new file mode 100644
index 00000000..befa7850
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/ethernet1/mac
@@ -0,0 +1 @@
+00:33:21:98:b9:f1
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/ethernet1/origin b/src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/ethernet1/origin
new file mode 100644
index 00000000..e440e5c8
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/ethernet1/origin
@@ -0,0 +1 @@
+3
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/ethernet1/primary-dns b/src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/ethernet1/primary-dns
new file mode 100644
index 00000000..2e152cb0
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/ethernet1/primary-dns
@@ -0,0 +1 @@
+10.16.255.2
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/ethernet1/secondary-dns b/src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/ethernet1/secondary-dns
new file mode 100644
index 00000000..2eb9e1d0
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/ethernet1/secondary-dns
@@ -0,0 +1 @@
+10.16.255.3
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/ethernet1/vlan b/src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/ethernet1/vlan
new file mode 100644
index 00000000..c2270834
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/ethernet1/vlan
@@ -0,0 +1 @@
+0
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/initiator/initiator-name b/src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/initiator/initiator-name
new file mode 100644
index 00000000..509a7ab8
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/initiator/initiator-name
@@ -0,0 +1 @@
+iqn.pjones6
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/target0/index b/src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/target0/index
new file mode 100644
index 00000000..c2270834
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/target0/index
@@ -0,0 +1 @@
+0
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/target0/ip-addr b/src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/target0/ip-addr
new file mode 100644
index 00000000..7450fdf9
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/target0/ip-addr
@@ -0,0 +1 @@
+10.16.52.16
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/target0/lun b/src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/target0/lun
new file mode 100644
index 00000000..c43d0930
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/target0/lun
@@ -0,0 +1 @@
+00000000
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/target0/port b/src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/target0/port
new file mode 100644
index 00000000..58f0d919
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/target0/port
@@ -0,0 +1 @@
+3260
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/target0/target-name b/src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/target0/target-name
new file mode 100644
index 00000000..32c9450a
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/target0/target-name
@@ -0,0 +1 @@
+iqn.0.2008-11.com.blahblah:iscsi0
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/target1/index b/src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/target1/index
new file mode 100644
index 00000000..56a6051c
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/target1/index
@@ -0,0 +1 @@
+1
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/target1/ip-addr b/src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/target1/ip-addr
new file mode 100644
index 00000000..7450fdf9
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/target1/ip-addr
@@ -0,0 +1 @@
+10.16.52.16
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/target1/lun b/src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/target1/lun
new file mode 100644
index 00000000..c43d0930
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/target1/lun
@@ -0,0 +1 @@
+00000000
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/target1/port b/src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/target1/port
new file mode 100644
index 00000000..58f0d919
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/target1/port
@@ -0,0 +1 @@
+3260
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/target1/target-name b/src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/target1/target-name
new file mode 100644
index 00000000..ac3a6a2a
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-dhcp/firmware/ibft/target1/target-name
@@ -0,0 +1 @@
+iqn.1.2008-11.com.blahblah:iscsi1
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-dt-tftp/firmware/devicetree/base/chosen/bootpath b/src/nm-initrd-generator/tests/sysfs-dt-tftp/firmware/devicetree/base/chosen/bootpath
new file mode 100644
index 00000000..6f069ae0
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-dt-tftp/firmware/devicetree/base/chosen/bootpath
Binary files differdiff --git a/src/nm-initrd-generator/tests/sysfs-dt/firmware/devicetree/base/chosen/bootp-request b/src/nm-initrd-generator/tests/sysfs-dt/firmware/devicetree/base/chosen/bootp-request
new file mode 100644
index 00000000..034d423e
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-dt/firmware/devicetree/base/chosen/bootp-request
Binary files differdiff --git a/src/nm-initrd-generator/tests/sysfs-dt/firmware/devicetree/base/chosen/bootp-response b/src/nm-initrd-generator/tests/sysfs-dt/firmware/devicetree/base/chosen/bootp-response
new file mode 100644
index 00000000..25982d6f
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-dt/firmware/devicetree/base/chosen/bootp-response
Binary files differdiff --git a/src/nm-initrd-generator/tests/sysfs-dt/firmware/devicetree/base/chosen/bootpath b/src/nm-initrd-generator/tests/sysfs-dt/firmware/devicetree/base/chosen/bootpath
new file mode 100644
index 00000000..db880702
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-dt/firmware/devicetree/base/chosen/bootpath
Binary files differdiff --git a/src/nm-initrd-generator/tests/sysfs-dt/firmware/devicetree/base/chosen/broadcast-ip b/src/nm-initrd-generator/tests/sysfs-dt/firmware/devicetree/base/chosen/broadcast-ip
new file mode 100644
index 00000000..7bde8641
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-dt/firmware/devicetree/base/chosen/broadcast-ip
@@ -0,0 +1 @@
+ÿÿÿÿ
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-dt/firmware/devicetree/base/chosen/client-ip b/src/nm-initrd-generator/tests/sysfs-dt/firmware/devicetree/base/chosen/client-ip
new file mode 100644
index 00000000..f108ba9b
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-dt/firmware/devicetree/base/chosen/client-ip
@@ -0,0 +1,2 @@
+
++
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-dt/firmware/devicetree/base/chosen/client-name b/src/nm-initrd-generator/tests/sysfs-dt/firmware/devicetree/base/chosen/client-name
new file mode 100644
index 00000000..fe0f76b8
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-dt/firmware/devicetree/base/chosen/client-name
Binary files differdiff --git a/src/nm-initrd-generator/tests/sysfs-dt/firmware/devicetree/base/chosen/domain-name b/src/nm-initrd-generator/tests/sysfs-dt/firmware/devicetree/base/chosen/domain-name
new file mode 100644
index 00000000..b34f9f96
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-dt/firmware/devicetree/base/chosen/domain-name
Binary files differdiff --git a/src/nm-initrd-generator/tests/sysfs-dt/firmware/devicetree/base/chosen/gateway-ip b/src/nm-initrd-generator/tests/sysfs-dt/firmware/devicetree/base/chosen/gateway-ip
new file mode 100644
index 00000000..f0361835
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-dt/firmware/devicetree/base/chosen/gateway-ip
@@ -0,0 +1,2 @@
+
++þ
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-dt/firmware/devicetree/base/chosen/name b/src/nm-initrd-generator/tests/sysfs-dt/firmware/devicetree/base/chosen/name
new file mode 100644
index 00000000..f3e58052
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-dt/firmware/devicetree/base/chosen/name
Binary files differdiff --git a/src/nm-initrd-generator/tests/sysfs-dt/firmware/devicetree/base/chosen/netmask-ip b/src/nm-initrd-generator/tests/sysfs-dt/firmware/devicetree/base/chosen/netmask-ip
new file mode 100644
index 00000000..d441cd83
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-dt/firmware/devicetree/base/chosen/netmask-ip
Binary files differdiff --git a/src/nm-initrd-generator/tests/sysfs-dt/firmware/devicetree/base/chosen/root-path b/src/nm-initrd-generator/tests/sysfs-dt/firmware/devicetree/base/chosen/root-path
new file mode 100644
index 00000000..f76dd238
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-dt/firmware/devicetree/base/chosen/root-path
Binary files differdiff --git a/src/nm-initrd-generator/tests/sysfs-dt/firmware/devicetree/base/chosen/server-ip b/src/nm-initrd-generator/tests/sysfs-dt/firmware/devicetree/base/chosen/server-ip
new file mode 100644
index 00000000..a2a4b2e8
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-dt/firmware/devicetree/base/chosen/server-ip
@@ -0,0 +1,2 @@
+
+&
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-dt/firmware/devicetree/base/chosen/tftp-file b/src/nm-initrd-generator/tests/sysfs-dt/firmware/devicetree/base/chosen/tftp-file
new file mode 100644
index 00000000..c0e0e330
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-dt/firmware/devicetree/base/chosen/tftp-file
Binary files differdiff --git a/src/nm-initrd-generator/tests/sysfs-dt/firmware/devicetree/base/chosen/vendor-options b/src/nm-initrd-generator/tests/sysfs-dt/firmware/devicetree/base/chosen/vendor-options
new file mode 100644
index 00000000..f76dd238
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-dt/firmware/devicetree/base/chosen/vendor-options
Binary files differdiff --git a/src/nm-initrd-generator/tests/sysfs-dt/firmware/devicetree/base/ethernet/device_type b/src/nm-initrd-generator/tests/sysfs-dt/firmware/devicetree/base/ethernet/device_type
new file mode 100644
index 00000000..df3c9d9f
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-dt/firmware/devicetree/base/ethernet/device_type
Binary files differdiff --git a/src/nm-initrd-generator/tests/sysfs-dt/firmware/devicetree/base/ethernet/local-mac-address b/src/nm-initrd-generator/tests/sysfs-dt/firmware/devicetree/base/ethernet/local-mac-address
new file mode 100644
index 00000000..c983e752
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-dt/firmware/devicetree/base/ethernet/local-mac-address
@@ -0,0 +1 @@
+¬>åØ
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-dt/firmware/devicetree/base/ethernet/mac-address b/src/nm-initrd-generator/tests/sysfs-dt/firmware/devicetree/base/ethernet/mac-address
new file mode 100644
index 00000000..c983e752
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-dt/firmware/devicetree/base/ethernet/mac-address
@@ -0,0 +1 @@
+¬>åØ
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-dt/firmware/devicetree/base/ethernet/name b/src/nm-initrd-generator/tests/sysfs-dt/firmware/devicetree/base/ethernet/name
new file mode 100644
index 00000000..88eaddfe
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-dt/firmware/devicetree/base/ethernet/name
Binary files differdiff --git a/src/nm-initrd-generator/tests/sysfs-static/class/net/eth0/address b/src/nm-initrd-generator/tests/sysfs-static/class/net/eth0/address
new file mode 100644
index 00000000..20659db7
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-static/class/net/eth0/address
@@ -0,0 +1 @@
+00:33:21:98:b9:f0
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-static/class/net/eth1/address b/src/nm-initrd-generator/tests/sysfs-static/class/net/eth1/address
new file mode 100644
index 00000000..befa7850
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-static/class/net/eth1/address
@@ -0,0 +1 @@
+00:33:21:98:b9:f1
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/ethernet0/gateway b/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/ethernet0/gateway
new file mode 100644
index 00000000..bf6cf454
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/ethernet0/gateway
@@ -0,0 +1 @@
+192.168.35.254
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/ethernet0/index b/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/ethernet0/index
new file mode 100644
index 00000000..c2270834
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/ethernet0/index
@@ -0,0 +1 @@
+0
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/ethernet0/ip-addr b/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/ethernet0/ip-addr
new file mode 100644
index 00000000..944c8d45
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/ethernet0/ip-addr
@@ -0,0 +1 @@
+192.168.32.72
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/ethernet0/mac b/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/ethernet0/mac
new file mode 100644
index 00000000..20659db7
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/ethernet0/mac
@@ -0,0 +1 @@
+00:33:21:98:b9:f0
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/ethernet0/origin b/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/ethernet0/origin
new file mode 100644
index 00000000..56a6051c
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/ethernet0/origin
@@ -0,0 +1 @@
+1
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/ethernet0/prefix-len b/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/ethernet0/prefix-len
new file mode 100644
index 00000000..8fdd954d
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/ethernet0/prefix-len
@@ -0,0 +1 @@
+22
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/ethernet0/primary-dns b/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/ethernet0/primary-dns
new file mode 100644
index 00000000..2e152cb0
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/ethernet0/primary-dns
@@ -0,0 +1 @@
+10.16.255.2
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/ethernet0/secondary-dns b/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/ethernet0/secondary-dns
new file mode 100644
index 00000000..2eb9e1d0
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/ethernet0/secondary-dns
@@ -0,0 +1 @@
+10.16.255.3
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/ethernet0/subnet-mask b/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/ethernet0/subnet-mask
new file mode 100644
index 00000000..7cb9d0a9
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/ethernet0/subnet-mask
@@ -0,0 +1 @@
+255.255.252.0
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/ethernet0/vlan b/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/ethernet0/vlan
new file mode 100644
index 00000000..c2270834
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/ethernet0/vlan
@@ -0,0 +1 @@
+0
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/ethernet1/gateway b/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/ethernet1/gateway
new file mode 100644
index 00000000..59ea5b82
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/ethernet1/gateway
@@ -0,0 +1 @@
+10.16.52.254
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/ethernet1/index b/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/ethernet1/index
new file mode 100644
index 00000000..56a6051c
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/ethernet1/index
@@ -0,0 +1 @@
+1
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/ethernet1/mac b/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/ethernet1/mac
new file mode 100644
index 00000000..befa7850
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/ethernet1/mac
@@ -0,0 +1 @@
+00:33:21:98:b9:f1
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/ethernet1/origin b/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/ethernet1/origin
new file mode 100644
index 00000000..e440e5c8
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/ethernet1/origin
@@ -0,0 +1 @@
+3
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/ethernet1/primary-dns b/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/ethernet1/primary-dns
new file mode 100644
index 00000000..2e152cb0
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/ethernet1/primary-dns
@@ -0,0 +1 @@
+10.16.255.2
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/ethernet1/secondary-dns b/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/ethernet1/secondary-dns
new file mode 100644
index 00000000..2eb9e1d0
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/ethernet1/secondary-dns
@@ -0,0 +1 @@
+10.16.255.3
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/ethernet1/vlan b/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/ethernet1/vlan
new file mode 100644
index 00000000..c2270834
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/ethernet1/vlan
@@ -0,0 +1 @@
+0
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/initiator/initiator-name b/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/initiator/initiator-name
new file mode 100644
index 00000000..509a7ab8
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/initiator/initiator-name
@@ -0,0 +1 @@
+iqn.pjones6
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/target0/index b/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/target0/index
new file mode 100644
index 00000000..c2270834
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/target0/index
@@ -0,0 +1 @@
+0
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/target0/ip-addr b/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/target0/ip-addr
new file mode 100644
index 00000000..7450fdf9
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/target0/ip-addr
@@ -0,0 +1 @@
+10.16.52.16
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/target0/lun b/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/target0/lun
new file mode 100644
index 00000000..c43d0930
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/target0/lun
@@ -0,0 +1 @@
+00000000
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/target0/port b/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/target0/port
new file mode 100644
index 00000000..58f0d919
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/target0/port
@@ -0,0 +1 @@
+3260
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/target0/target-name b/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/target0/target-name
new file mode 100644
index 00000000..32c9450a
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/target0/target-name
@@ -0,0 +1 @@
+iqn.0.2008-11.com.blahblah:iscsi0
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/target1/index b/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/target1/index
new file mode 100644
index 00000000..56a6051c
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/target1/index
@@ -0,0 +1 @@
+1
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/target1/ip-addr b/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/target1/ip-addr
new file mode 100644
index 00000000..7450fdf9
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/target1/ip-addr
@@ -0,0 +1 @@
+10.16.52.16
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/target1/lun b/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/target1/lun
new file mode 100644
index 00000000..c43d0930
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/target1/lun
@@ -0,0 +1 @@
+00000000
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/target1/port b/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/target1/port
new file mode 100644
index 00000000..58f0d919
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/target1/port
@@ -0,0 +1 @@
+3260
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/target1/target-name b/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/target1/target-name
new file mode 100644
index 00000000..ac3a6a2a
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-static/firmware/ibft/target1/target-name
@@ -0,0 +1 @@
+iqn.1.2008-11.com.blahblah:iscsi1
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-vlan/class/net/eth0/address b/src/nm-initrd-generator/tests/sysfs-vlan/class/net/eth0/address
new file mode 100644
index 00000000..20659db7
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-vlan/class/net/eth0/address
@@ -0,0 +1 @@
+00:33:21:98:b9:f0
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-vlan/firmware/ibft/ethernet0/index b/src/nm-initrd-generator/tests/sysfs-vlan/firmware/ibft/ethernet0/index
new file mode 100644
index 00000000..c2270834
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-vlan/firmware/ibft/ethernet0/index
@@ -0,0 +1 @@
+0
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-vlan/firmware/ibft/ethernet0/ip-addr b/src/nm-initrd-generator/tests/sysfs-vlan/firmware/ibft/ethernet0/ip-addr
new file mode 100644
index 00000000..4923230c
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-vlan/firmware/ibft/ethernet0/ip-addr
@@ -0,0 +1 @@
+192.168.6.200
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-vlan/firmware/ibft/ethernet0/mac b/src/nm-initrd-generator/tests/sysfs-vlan/firmware/ibft/ethernet0/mac
new file mode 100644
index 00000000..20659db7
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-vlan/firmware/ibft/ethernet0/mac
@@ -0,0 +1 @@
+00:33:21:98:b9:f0
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-vlan/firmware/ibft/ethernet0/origin b/src/nm-initrd-generator/tests/sysfs-vlan/firmware/ibft/ethernet0/origin
new file mode 100644
index 00000000..56a6051c
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-vlan/firmware/ibft/ethernet0/origin
@@ -0,0 +1 @@
+1
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-vlan/firmware/ibft/ethernet0/prefix-len b/src/nm-initrd-generator/tests/sysfs-vlan/firmware/ibft/ethernet0/prefix-len
new file mode 100644
index 00000000..cabf43b5
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-vlan/firmware/ibft/ethernet0/prefix-len
@@ -0,0 +1 @@
+24
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-vlan/firmware/ibft/ethernet0/subnet-mask b/src/nm-initrd-generator/tests/sysfs-vlan/firmware/ibft/ethernet0/subnet-mask
new file mode 100644
index 00000000..5a279b41
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-vlan/firmware/ibft/ethernet0/subnet-mask
@@ -0,0 +1 @@
+255.255.255.0
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-vlan/firmware/ibft/ethernet0/vlan b/src/nm-initrd-generator/tests/sysfs-vlan/firmware/ibft/ethernet0/vlan
new file mode 100644
index 00000000..d800886d
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-vlan/firmware/ibft/ethernet0/vlan
@@ -0,0 +1 @@
+123
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-vlan/firmware/ibft/initiator/initiator-name b/src/nm-initrd-generator/tests/sysfs-vlan/firmware/ibft/initiator/initiator-name
new file mode 100644
index 00000000..8e9cd2c4
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-vlan/firmware/ibft/initiator/initiator-name
@@ -0,0 +1 @@
+iqn.2010-04.org.ipxe:d05faa97-c4be-44f6-a723-efde9aa399a0
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-vlan/firmware/ibft/target0/index b/src/nm-initrd-generator/tests/sysfs-vlan/firmware/ibft/target0/index
new file mode 100644
index 00000000..c2270834
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-vlan/firmware/ibft/target0/index
@@ -0,0 +1 @@
+0
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-vlan/firmware/ibft/target0/ip-addr b/src/nm-initrd-generator/tests/sysfs-vlan/firmware/ibft/target0/ip-addr
new file mode 100644
index 00000000..a32ce01b
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-vlan/firmware/ibft/target0/ip-addr
@@ -0,0 +1 @@
+192.168.6.32
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-vlan/firmware/ibft/target0/lun b/src/nm-initrd-generator/tests/sysfs-vlan/firmware/ibft/target0/lun
new file mode 100644
index 00000000..f309ca6a
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-vlan/firmware/ibft/target0/lun
@@ -0,0 +1 @@
+01000000
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-vlan/firmware/ibft/target0/port b/src/nm-initrd-generator/tests/sysfs-vlan/firmware/ibft/target0/port
new file mode 100644
index 00000000..58f0d919
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-vlan/firmware/ibft/target0/port
@@ -0,0 +1 @@
+3260
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs-vlan/firmware/ibft/target0/target-name b/src/nm-initrd-generator/tests/sysfs-vlan/firmware/ibft/target0/target-name
new file mode 100644
index 00000000..f0e61157
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs-vlan/firmware/ibft/target0/target-name
@@ -0,0 +1 @@
+iqn.2003-01.org.x:disk1
\ No newline at end of file
diff --git a/src/nm-initrd-generator/tests/sysfs/class/net/eth0/address b/src/nm-initrd-generator/tests/sysfs/class/net/eth0/address
new file mode 100644
index 00000000..1f2f610e
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs/class/net/eth0/address
@@ -0,0 +1 @@
+00:53:00:AB:00:01
diff --git a/src/nm-initrd-generator/tests/sysfs/class/net/eth2/address b/src/nm-initrd-generator/tests/sysfs/class/net/eth2/address
new file mode 100644
index 00000000..6ec1078a
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs/class/net/eth2/address
@@ -0,0 +1 @@
+00:53:06:66:ab:01
diff --git a/src/nm-initrd-generator/tests/sysfs/firmware/ibft/acpi_header/oem_id b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/acpi_header/oem_id
new file mode 100644
index 00000000..590d9cd2
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/acpi_header/oem_id
@@ -0,0 +1 @@
+NMTst
diff --git a/src/nm-initrd-generator/tests/sysfs/firmware/ibft/acpi_header/oem_table_id b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/acpi_header/oem_table_id
new file mode 100644
index 00000000..35d4d09c
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/acpi_header/oem_table_id
@@ -0,0 +1 @@
+Whatevs
diff --git a/src/nm-initrd-generator/tests/sysfs/firmware/ibft/acpi_header/signature b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/acpi_header/signature
new file mode 100644
index 00000000..e3a5d7ef
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/acpi_header/signature
@@ -0,0 +1 @@
+IBFT
diff --git a/src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet0/dhcp b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet0/dhcp
new file mode 100644
index 00000000..98a0d797
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet0/dhcp
@@ -0,0 +1 @@
+2001:0db8:0000:0000:0000:0000:0000:0002
diff --git a/src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet0/flags b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet0/flags
new file mode 100644
index 00000000..00750edc
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet0/flags
@@ -0,0 +1 @@
+3
diff --git a/src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet0/gateway b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet0/gateway
new file mode 100644
index 00000000..7f378f8f
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet0/gateway
@@ -0,0 +1 @@
+2001:0db8:0000:0000:0000:0000:0000:0001
diff --git a/src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet0/hostname b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet0/hostname
new file mode 100644
index 00000000..3ed5163c
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet0/hostname
@@ -0,0 +1 @@
+host0.example.com
diff --git a/src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet0/index b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet0/index
new file mode 100644
index 00000000..573541ac
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet0/index
@@ -0,0 +1 @@
+0
diff --git a/src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet0/ip-addr b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet0/ip-addr
new file mode 100644
index 00000000..98a0d797
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet0/ip-addr
@@ -0,0 +1 @@
+2001:0db8:0000:0000:0000:0000:0000:0002
diff --git a/src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet0/mac b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet0/mac
new file mode 100644
index 00000000..f2441319
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet0/mac
@@ -0,0 +1 @@
+00:53:00:ab:00:01
diff --git a/src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet0/origin b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet0/origin
new file mode 100644
index 00000000..b8626c4c
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet0/origin
@@ -0,0 +1 @@
+4
diff --git a/src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet0/prefix-len b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet0/prefix-len
new file mode 100644
index 00000000..900731ff
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet0/prefix-len
@@ -0,0 +1 @@
+64
diff --git a/src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet0/primary-dns b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet0/primary-dns
new file mode 100644
index 00000000..e7511d5a
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet0/primary-dns
@@ -0,0 +1 @@
+2001:0db8:0000:0000:0000:0000:0000:0053
diff --git a/src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet0/secondary-dns b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet0/secondary-dns
new file mode 100644
index 00000000..1f6c5c95
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet0/secondary-dns
@@ -0,0 +1 @@
+2001:0db8:0000:0000:0000:0000:0000:5353
diff --git a/src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet0/subnet-mask b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet0/subnet-mask
new file mode 100644
index 00000000..5df93454
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet0/subnet-mask
@@ -0,0 +1 @@
+255.255.255.255
diff --git a/src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet0/vlan b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet0/vlan
new file mode 100644
index 00000000..7cc86ad1
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet0/vlan
@@ -0,0 +1 @@
+666
diff --git a/src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet2/dhcp b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet2/dhcp
new file mode 100644
index 00000000..61ef5585
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet2/dhcp
@@ -0,0 +1 @@
+192.0.2.2
diff --git a/src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet2/flags b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet2/flags
new file mode 100644
index 00000000..00750edc
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet2/flags
@@ -0,0 +1 @@
+3
diff --git a/src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet2/gateway b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet2/gateway
new file mode 100644
index 00000000..2096f194
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet2/gateway
@@ -0,0 +1 @@
+192.0.2.1
diff --git a/src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet2/hostname b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet2/hostname
new file mode 100644
index 00000000..5dc539d5
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet2/hostname
@@ -0,0 +1 @@
+host2.example.com
diff --git a/src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet2/index b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet2/index
new file mode 100644
index 00000000..0cfbf088
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet2/index
@@ -0,0 +1 @@
+2
diff --git a/src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet2/ip-addr b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet2/ip-addr
new file mode 100644
index 00000000..61ef5585
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet2/ip-addr
@@ -0,0 +1 @@
+192.0.2.2
diff --git a/src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet2/mac b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet2/mac
new file mode 100644
index 00000000..2fc3d525
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet2/mac
@@ -0,0 +1 @@
+00:53:06:66:AB:01
diff --git a/src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet2/origin b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet2/origin
new file mode 100644
index 00000000..00750edc
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet2/origin
@@ -0,0 +1 @@
+3
diff --git a/src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet2/prefix-len b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet2/prefix-len
new file mode 100644
index 00000000..a45fd52c
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet2/prefix-len
@@ -0,0 +1 @@
+24
diff --git a/src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet2/primary-dns b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet2/primary-dns
new file mode 100644
index 00000000..6fa8c742
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet2/primary-dns
@@ -0,0 +1 @@
+192.0.2.53
diff --git a/src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet2/secondary-dns b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet2/secondary-dns
new file mode 100644
index 00000000..a7269ff5
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet2/secondary-dns
@@ -0,0 +1 @@
+192.0.2.54
diff --git a/src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet2/subnet-mask b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet2/subnet-mask
new file mode 100644
index 00000000..d30f9e9f
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet2/subnet-mask
@@ -0,0 +1 @@
+255.255.255.0
diff --git a/src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet2/vlan b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet2/vlan
new file mode 100644
index 00000000..573541ac
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/ethernet2/vlan
@@ -0,0 +1 @@
+0
diff --git a/src/nm-initrd-generator/tests/sysfs/firmware/ibft/initiator/flags b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/initiator/flags
new file mode 100644
index 00000000..00750edc
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/initiator/flags
@@ -0,0 +1 @@
+3
diff --git a/src/nm-initrd-generator/tests/sysfs/firmware/ibft/initiator/index b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/initiator/index
new file mode 100644
index 00000000..573541ac
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/initiator/index
@@ -0,0 +1 @@
+0
diff --git a/src/nm-initrd-generator/tests/sysfs/firmware/ibft/initiator/initiator-name b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/initiator/initiator-name
new file mode 100644
index 00000000..337b5a0f
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/initiator/initiator-name
@@ -0,0 +1 @@
+iqn.1994-05.com.example.initiator:48b055856417
diff --git a/src/nm-initrd-generator/tests/sysfs/firmware/ibft/initiator/isns-server b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/initiator/isns-server
new file mode 100644
index 00000000..4aff9398
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/initiator/isns-server
@@ -0,0 +1 @@
+2001:0db8:0000:0000:0000:0000:0000:3205
diff --git a/src/nm-initrd-generator/tests/sysfs/firmware/ibft/initiator/pri-radius-server b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/initiator/pri-radius-server
new file mode 100644
index 00000000..a26fb649
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/initiator/pri-radius-server
@@ -0,0 +1 @@
+2001:0db8:0000:0000:0000:0000:0000:1812
diff --git a/src/nm-initrd-generator/tests/sysfs/firmware/ibft/initiator/sec-radius-server b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/initiator/sec-radius-server
new file mode 100644
index 00000000..908be27f
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/initiator/sec-radius-server
@@ -0,0 +1 @@
+192.0.2.181
diff --git a/src/nm-initrd-generator/tests/sysfs/firmware/ibft/initiator/slp-server b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/initiator/slp-server
new file mode 100644
index 00000000..fca9e24b
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/initiator/slp-server
@@ -0,0 +1 @@
+2001:0db8:0000:0000:0000:0000:0000:0427
diff --git a/src/nm-initrd-generator/tests/sysfs/firmware/ibft/target0/chap-type b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/target0/chap-type
new file mode 100644
index 00000000..573541ac
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/target0/chap-type
@@ -0,0 +1 @@
+0
diff --git a/src/nm-initrd-generator/tests/sysfs/firmware/ibft/target0/flags b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/target0/flags
new file mode 100644
index 00000000..00750edc
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/target0/flags
@@ -0,0 +1 @@
+3
diff --git a/src/nm-initrd-generator/tests/sysfs/firmware/ibft/target0/index b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/target0/index
new file mode 100644
index 00000000..573541ac
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/target0/index
@@ -0,0 +1 @@
+0
diff --git a/src/nm-initrd-generator/tests/sysfs/firmware/ibft/target0/ip-addr b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/target0/ip-addr
new file mode 100644
index 00000000..994b6e9c
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/target0/ip-addr
@@ -0,0 +1 @@
+2001:0db8:0000:0000:0000:0000:0000:3260
diff --git a/src/nm-initrd-generator/tests/sysfs/firmware/ibft/target0/lun b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/target0/lun
new file mode 100644
index 00000000..7c295bd4
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/target0/lun
@@ -0,0 +1 @@
+01000000
diff --git a/src/nm-initrd-generator/tests/sysfs/firmware/ibft/target0/nic-assoc b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/target0/nic-assoc
new file mode 100644
index 00000000..573541ac
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/target0/nic-assoc
@@ -0,0 +1 @@
+0
diff --git a/src/nm-initrd-generator/tests/sysfs/firmware/ibft/target0/port b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/target0/port
new file mode 100644
index 00000000..53f0295f
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/target0/port
@@ -0,0 +1 @@
+3260
diff --git a/src/nm-initrd-generator/tests/sysfs/firmware/ibft/target2/chap-type b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/target2/chap-type
new file mode 100644
index 00000000..573541ac
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/target2/chap-type
@@ -0,0 +1 @@
+0
diff --git a/src/nm-initrd-generator/tests/sysfs/firmware/ibft/target2/flags b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/target2/flags
new file mode 100644
index 00000000..00750edc
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/target2/flags
@@ -0,0 +1 @@
+3
diff --git a/src/nm-initrd-generator/tests/sysfs/firmware/ibft/target2/index b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/target2/index
new file mode 100644
index 00000000..0cfbf088
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/target2/index
@@ -0,0 +1 @@
+2
diff --git a/src/nm-initrd-generator/tests/sysfs/firmware/ibft/target2/ip-addr b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/target2/ip-addr
new file mode 100644
index 00000000..a210477e
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/target2/ip-addr
@@ -0,0 +1 @@
+2001:0db8:0000:0000:0000:0000:0002:3260
diff --git a/src/nm-initrd-generator/tests/sysfs/firmware/ibft/target2/lun b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/target2/lun
new file mode 100644
index 00000000..7c295bd4
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/target2/lun
@@ -0,0 +1 @@
+01000000
diff --git a/src/nm-initrd-generator/tests/sysfs/firmware/ibft/target2/nic-assoc b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/target2/nic-assoc
new file mode 100644
index 00000000..0cfbf088
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/target2/nic-assoc
@@ -0,0 +1 @@
+2
diff --git a/src/nm-initrd-generator/tests/sysfs/firmware/ibft/target2/port b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/target2/port
new file mode 100644
index 00000000..53f0295f
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/target2/port
@@ -0,0 +1 @@
+3260
diff --git a/src/nm-initrd-generator/tests/sysfs/firmware/ibft/target2/target-name b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/target2/target-name
new file mode 100644
index 00000000..f4094320
--- /dev/null
+++ b/src/nm-initrd-generator/tests/sysfs/firmware/ibft/target2/target-name
@@ -0,0 +1 @@
+iqn.1994-05.com.example.target:48b055851337
diff --git a/src/nm-initrd-generator/tests/test-cmdline-reader.c b/src/nm-initrd-generator/tests/test-cmdline-reader.c
new file mode 100644
index 00000000..e2a37c58
--- /dev/null
+++ b/src/nm-initrd-generator/tests/test-cmdline-reader.c
@@ -0,0 +1,2552 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ */
+
+#include "src/core/nm-default-daemon.h"
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/socket.h>
+
+#include "libnm-core-intern/nm-core-internal.h"
+
+#include "nm-initrd-generator/nm-initrd-generator.h"
+
+#include "libnm-glib-aux/nm-test-utils.h"
+
+#define TEST_INITRD_DIR NM_BUILD_SRCDIR "/src/nm-initrd-generator/tests"
+
+/*****************************************************************************/
+
+#define _parse(ARGV, out_hostname, out_carrier_timeout_sec)                            \
+    ({                                                                                 \
+        const char *const *const _ARGV                    = (ARGV);                    \
+        char **const             _out_hostname            = (out_hostname);            \
+        gint64 *const            _out_carrier_timeout_sec = (out_carrier_timeout_sec); \
+        GHashTable *             _connections;                                         \
+                                                                                       \
+        _connections = nmi_cmdline_reader_parse(TEST_INITRD_DIR "/sysfs",              \
+                                                _ARGV,                                 \
+                                                _out_hostname,                         \
+                                                _out_carrier_timeout_sec);             \
+                                                                                       \
+        g_assert(_connections);                                                        \
+                                                                                       \
+        _connections;                                                                  \
+    })
+
+#define _parse_cons(ARGV)                                                                    \
+    ({                                                                                       \
+        GHashTable *  _con_connections;                                                      \
+        gs_free char *_con_hostname            = NULL;                                       \
+        gint64        _con_carrier_timeout_sec = 0;                                          \
+                                                                                             \
+        _con_connections = _parse((ARGV),                                                    \
+                                  nmtst_get_rand_bool() ? &_con_hostname : NULL,             \
+                                  nmtst_get_rand_bool() ? &_con_carrier_timeout_sec : NULL); \
+        g_assert_cmpstr(_con_hostname, ==, NULL);                                            \
+        g_assert_cmpint(_con_carrier_timeout_sec, ==, 0);                                    \
+                                                                                             \
+        _con_connections;                                                                    \
+    })
+
+#define _parse_con(ARGV, connection_name)                                        \
+    ({                                                                           \
+        gs_unref_hashtable GHashTable *_1_connections = NULL;                    \
+        NMConnection *                 _1_connection;                            \
+        const char *const              _1_connection_name = (connection_name);   \
+                                                                                 \
+        g_assert(_1_connection_name);                                            \
+                                                                                 \
+        _1_connections = _parse_cons((ARGV));                                    \
+                                                                                 \
+        g_assert_cmpint(g_hash_table_size(_1_connections), ==, 1);               \
+                                                                                 \
+        _1_connection = g_hash_table_lookup(_1_connections, _1_connection_name); \
+        g_assert(NM_IS_CONNECTION(_1_connection));                               \
+                                                                                 \
+        nmtst_assert_connection_verifies_without_normalization(_1_connection);   \
+                                                                                 \
+        NM_CONNECTION(g_object_ref(_1_connection));                              \
+    })
+
+#define _parse_no_con(ARGV)                                        \
+    G_STMT_START                                                   \
+    {                                                              \
+        gs_unref_hashtable GHashTable *_0_connections = NULL;      \
+                                                                   \
+        _0_connections = _parse_cons(ARGV);                        \
+        g_assert_cmpint(g_hash_table_size(_0_connections), ==, 0); \
+    }                                                              \
+    G_STMT_END
+
+/*****************************************************************************/
+
+static void
+test_auto(void)
+{
+    const char *const *ARGV                  = NM_MAKE_STRV("ip=auto");
+    gs_unref_object NMConnection *connection = NULL;
+    NMSettingConnection *         s_con;
+    NMSettingWired *              s_wired;
+    NMSettingIPConfig *           s_ip4;
+    NMSettingIPConfig *           s_ip6;
+
+    connection = _parse_con(ARGV, "default_connection");
+
+    g_assert(!nm_connection_get_setting_vlan(connection));
+
+    s_con = nm_connection_get_setting_connection(connection);
+    g_assert(s_con);
+    g_assert_cmpstr(nm_setting_connection_get_connection_type(s_con),
+                    ==,
+                    NM_SETTING_WIRED_SETTING_NAME);
+    g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "Wired Connection");
+    g_assert_cmpint(nm_setting_connection_get_timestamp(s_con), ==, 0);
+    g_assert_cmpint(nm_setting_connection_get_multi_connect(s_con),
+                    ==,
+                    NM_CONNECTION_MULTI_CONNECT_MULTIPLE);
+    g_assert_cmpint(nm_setting_connection_get_wait_device_timeout(s_con), ==, -1);
+
+    g_assert(nm_setting_connection_get_autoconnect(s_con));
+
+    s_wired = nm_connection_get_setting_wired(connection);
+    g_assert(s_wired);
+    g_assert(!nm_setting_wired_get_mac_address(s_wired));
+    g_assert_cmpint(nm_setting_wired_get_mtu(s_wired), ==, 0);
+
+    s_ip4 = nm_connection_get_setting_ip4_config(connection);
+    g_assert(s_ip4);
+    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_AUTO);
+    g_assert(!nm_setting_ip_config_get_ignore_auto_dns(s_ip4));
+    g_assert_cmpint(nm_setting_ip_config_get_num_dns(s_ip4), ==, 0);
+    g_assert_cmpint(nm_setting_ip_config_get_num_addresses(s_ip4), ==, 0);
+    g_assert(!nm_setting_ip_config_get_gateway(s_ip4));
+
+    s_ip6 = nm_connection_get_setting_ip6_config(connection);
+    g_assert(s_ip6);
+    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_AUTO);
+    g_assert(!nm_setting_ip_config_get_ignore_auto_dns(s_ip6));
+    g_assert_cmpint(nm_setting_ip_config_get_num_dns(s_ip6), ==, 0);
+    g_assert_cmpint(nm_setting_ip_config_get_num_addresses(s_ip6), ==, 0);
+    g_assert(!nm_setting_ip_config_get_gateway(s_ip6));
+}
+
+static void
+test_dhcp_with_hostname(void)
+{
+    gs_unref_hashtable GHashTable *connections = NULL;
+    const char *const *            ARGV        = NM_MAKE_STRV("ip=::::host1::dhcp");
+    NMConnection *                 connection;
+    NMSettingConnection *          s_con;
+    NMSettingWired *               s_wired;
+    NMSettingIPConfig *            s_ip4;
+    NMSettingIPConfig *            s_ip6;
+    gs_free char *                 hostname            = NULL;
+    gint64                         carrier_timeout_sec = 0;
+
+    connections = _parse(ARGV, &hostname, &carrier_timeout_sec);
+    g_assert_cmpint(g_hash_table_size(connections), ==, 1);
+    g_assert_cmpstr(hostname, ==, "host1");
+    g_assert_cmpint(carrier_timeout_sec, ==, 0);
+
+    connection = g_hash_table_lookup(connections, "default_connection");
+
+    nmtst_assert_connection_verifies_without_normalization(connection);
+
+    g_assert(!nm_connection_get_setting_vlan(connection));
+
+    s_con = nm_connection_get_setting_connection(connection);
+    g_assert(s_con);
+    g_assert_cmpstr(nm_setting_connection_get_connection_type(s_con),
+                    ==,
+                    NM_SETTING_WIRED_SETTING_NAME);
+    g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "Wired Connection");
+    g_assert_cmpint(nm_setting_connection_get_timestamp(s_con), ==, 0);
+    g_assert_cmpint(nm_setting_connection_get_multi_connect(s_con),
+                    ==,
+                    NM_CONNECTION_MULTI_CONNECT_MULTIPLE);
+    g_assert_cmpint(nm_setting_connection_get_wait_device_timeout(s_con), ==, -1);
+
+    g_assert(nm_setting_connection_get_autoconnect(s_con));
+
+    s_wired = nm_connection_get_setting_wired(connection);
+    g_assert(s_wired);
+    g_assert(!nm_setting_wired_get_mac_address(s_wired));
+    g_assert_cmpint(nm_setting_wired_get_mtu(s_wired), ==, 0);
+
+    s_ip4 = nm_connection_get_setting_ip4_config(connection);
+    g_assert(s_ip4);
+    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_AUTO);
+
+    s_ip6 = nm_connection_get_setting_ip6_config(connection);
+    g_assert(s_ip6);
+    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_AUTO);
+}
+
+static void
+test_dhcp_with_mtu(void)
+{
+    const char *const *ARGV0  = NM_MAKE_STRV("ip=:dhcp:1499");
+    const char *const *ARGV1  = NM_MAKE_STRV("ip=::::::dhcp:1499");
+    const char *const *ARGV[] = {ARGV0, ARGV1};
+    guint              i;
+
+    for (i = 0; i < G_N_ELEMENTS(ARGV); i++) {
+        gs_unref_object NMConnection *connection = NULL;
+        NMSettingConnection *         s_con;
+        NMSettingWired *              s_wired;
+        NMSettingIPConfig *           s_ip4;
+        NMSettingIPConfig *           s_ip6;
+
+        connection = _parse_con(ARGV[i], "default_connection");
+
+        s_con = nm_connection_get_setting_connection(connection);
+        g_assert(s_con);
+        g_assert_cmpstr(nm_setting_connection_get_connection_type(s_con),
+                        ==,
+                        NM_SETTING_WIRED_SETTING_NAME);
+        g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "Wired Connection");
+        g_assert_cmpint(nm_setting_connection_get_timestamp(s_con), ==, 0);
+        g_assert_cmpint(nm_setting_connection_get_multi_connect(s_con),
+                        ==,
+                        NM_CONNECTION_MULTI_CONNECT_MULTIPLE);
+        g_assert_cmpint(nm_setting_connection_get_wait_device_timeout(s_con), ==, -1);
+
+        g_assert(nm_setting_connection_get_autoconnect(s_con));
+
+        s_wired = nm_connection_get_setting_wired(connection);
+        g_assert(s_wired);
+        g_assert(!nm_setting_wired_get_mac_address(s_wired));
+        g_assert_cmpint(nm_setting_wired_get_mtu(s_wired), ==, 1499);
+
+        s_ip4 = nm_connection_get_setting_ip4_config(connection);
+        g_assert(s_ip4);
+        g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4),
+                        ==,
+                        NM_SETTING_IP4_CONFIG_METHOD_AUTO);
+
+        s_ip6 = nm_connection_get_setting_ip6_config(connection);
+        g_assert(s_ip6);
+        g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6),
+                        ==,
+                        NM_SETTING_IP6_CONFIG_METHOD_AUTO);
+    }
+}
+
+static void
+test_dhcp_timeout(void)
+{
+    struct {
+        const char *const *cmdline;
+        int                timeout;
+    } data[] = {
+        {NM_MAKE_STRV("ip=dhcp"), 90},
+        {NM_MAKE_STRV("ip=dhcp", "rd.net.timeout.dhcp=0"), 90},
+        {NM_MAKE_STRV("ip=dhcp", "rd.net.timeout.dhcp=foobar"), 90},
+        {NM_MAKE_STRV("ip=dhcp", "rd.net.timeout.dhcp=42"), 42},
+        {NM_MAKE_STRV("ip=dhcp", "rd.net.dhcp.retry=2"), 180},
+        {NM_MAKE_STRV("ip=dhcp", "rd.net.dhcp.retry=3", "rd.net.timeout.dhcp=40"), 120},
+        {NM_MAKE_STRV("ip=dhcp", "rd.net.timeout.dhcp=infinity"), G_MAXINT32},
+        {NM_MAKE_STRV("ip=dhcp", "rd.net.timeout.dhcp=infinity", "rd.net.dhcp.retry=100"),
+         G_MAXINT32},
+    };
+    guint i;
+
+    for (i = 0; i < G_N_ELEMENTS(data); i++) {
+        gs_unref_object NMConnection *connection = NULL;
+        NMSettingConnection *         s_con;
+        NMSettingIPConfig *           s_ip4;
+        NMSettingIPConfig *           s_ip6;
+
+        connection = _parse_con(data[i].cmdline, "default_connection");
+
+        s_con = nm_connection_get_setting_connection(connection);
+        g_assert(s_con);
+        g_assert_cmpstr(nm_setting_connection_get_connection_type(s_con),
+                        ==,
+                        NM_SETTING_WIRED_SETTING_NAME);
+        g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "Wired Connection");
+        g_assert_cmpint(nm_setting_connection_get_timestamp(s_con), ==, 0);
+        g_assert_cmpint(nm_setting_connection_get_multi_connect(s_con),
+                        ==,
+                        NM_CONNECTION_MULTI_CONNECT_MULTIPLE);
+        g_assert_cmpint(nm_setting_connection_get_wait_device_timeout(s_con), ==, -1);
+        g_assert_cmpint(nm_setting_connection_get_autoconnect_retries(s_con), ==, 1);
+        g_assert(nm_setting_connection_get_autoconnect(s_con));
+
+        s_ip4 = nm_connection_get_setting_ip4_config(connection);
+        g_assert(s_ip4);
+        g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4),
+                        ==,
+                        NM_SETTING_IP4_CONFIG_METHOD_AUTO);
+        g_assert_cmpint(nm_setting_ip_config_get_dhcp_timeout(s_ip4), ==, data[i].timeout);
+        g_assert_cmpint(nm_setting_ip_config_get_required_timeout(s_ip4), ==, -1);
+
+        s_ip6 = nm_connection_get_setting_ip6_config(connection);
+        g_assert(s_ip6);
+        g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6),
+                        ==,
+                        NM_SETTING_IP6_CONFIG_METHOD_AUTO);
+        g_assert_cmpint(nm_setting_ip_config_get_dhcp_timeout(s_ip6), ==, data[i].timeout);
+        g_assert_cmpint(nm_setting_ip_config_get_required_timeout(s_ip6), ==, -1);
+    }
+}
+
+static void
+test_if_auto_with_mtu(void)
+{
+    const char *const *ARGV                  = NM_MAKE_STRV("ip=eth0:auto:1666", "=");
+    gs_unref_object NMConnection *connection = NULL;
+    NMSettingConnection *         s_con;
+    NMSettingWired *              s_wired;
+    NMSettingIPConfig *           s_ip4;
+    NMSettingIPConfig *           s_ip6;
+
+    connection = _parse_con(ARGV, "eth0");
+
+    g_assert_cmpstr(nm_connection_get_id(connection), ==, "eth0");
+
+    s_con = nm_connection_get_setting_connection(connection);
+    g_assert(s_con);
+    g_assert_cmpint(nm_setting_connection_get_autoconnect_retries(s_con), ==, 1);
+
+    s_wired = nm_connection_get_setting_wired(connection);
+    g_assert(s_wired);
+    g_assert_cmpint(nm_setting_wired_get_mtu(s_wired), ==, 1666);
+
+    s_ip4 = nm_connection_get_setting_ip4_config(connection);
+    g_assert(s_ip4);
+    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_AUTO);
+    g_assert(!nm_setting_ip_config_get_ignore_auto_dns(s_ip4));
+    g_assert_cmpint(nm_setting_ip_config_get_dhcp_timeout(s_ip4), ==, 90);
+
+    s_ip6 = nm_connection_get_setting_ip6_config(connection);
+    g_assert(s_ip6);
+    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_AUTO);
+    g_assert(!nm_setting_ip_config_get_ignore_auto_dns(s_ip6));
+}
+
+static void
+test_if_dhcp6(void)
+{
+    const char *const *ARGV                  = NM_MAKE_STRV("ip=eth1:dhcp6");
+    gs_unref_object NMConnection *connection = NULL;
+    NMSettingIPConfig *           s_ip4;
+    NMSettingIPConfig *           s_ip6;
+
+    connection = _parse_con(ARGV, "eth1");
+
+    g_assert_cmpstr(nm_connection_get_id(connection), ==, "eth1");
+
+    s_ip4 = nm_connection_get_setting_ip4_config(connection);
+    g_assert(s_ip4);
+    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4),
+                    ==,
+                    NM_SETTING_IP4_CONFIG_METHOD_DISABLED);
+    g_assert(!nm_setting_ip_config_get_ignore_auto_dns(s_ip4));
+
+    s_ip6 = nm_connection_get_setting_ip6_config(connection);
+    g_assert(s_ip6);
+    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_AUTO);
+    g_assert(!nm_setting_ip_config_get_ignore_auto_dns(s_ip6));
+}
+
+static void
+test_if_auto_with_mtu_and_mac(void)
+{
+    const char *const *ARGV                  = NM_MAKE_STRV("ip=eth2:auto6:2048:00:53:ef:12:34:56");
+    gs_unref_object NMConnection *connection = NULL;
+    NMSettingWired *              s_wired;
+    NMSettingIPConfig *           s_ip4;
+    NMSettingIPConfig *           s_ip6;
+
+    connection = _parse_con(ARGV, "eth2");
+
+    g_assert_cmpstr(nm_connection_get_id(connection), ==, "eth2");
+
+    s_wired = nm_connection_get_setting_wired(connection);
+    g_assert(s_wired);
+    g_assert_cmpint(nm_setting_wired_get_mtu(s_wired), ==, 2048);
+    g_assert_cmpstr(nm_setting_wired_get_cloned_mac_address(s_wired), ==, "00:53:EF:12:34:56");
+
+    s_ip4 = nm_connection_get_setting_ip4_config(connection);
+    g_assert(s_ip4);
+    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4),
+                    ==,
+                    NM_SETTING_IP4_CONFIG_METHOD_DISABLED);
+    g_assert(!nm_setting_ip_config_get_ignore_auto_dns(s_ip4));
+
+    s_ip6 = nm_connection_get_setting_ip6_config(connection);
+    g_assert(s_ip6);
+    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_AUTO);
+    g_assert(!nm_setting_ip_config_get_ignore_auto_dns(s_ip6));
+}
+
+static void
+test_if_ip4_manual(void)
+{
+    gs_unref_hashtable GHashTable *connections = NULL;
+    const char *const *            ARGV = NM_MAKE_STRV("ip=192.0.2.2::192.0.2.1:255.255.255.0:"
+                                           "hostname0.example.com:eth3:none:192.0.2.53",
+                                           "ip=203.0.113.2::203.0.113.1:26:"
+                                           "hostname1.example.com:eth4");
+    NMConnection *                 connection;
+    NMSettingConnection *          s_con;
+    NMSettingIPConfig *            s_ip4;
+    NMSettingIPConfig *            s_ip6;
+    NMIPAddress *                  ip_addr;
+    gs_free char *                 hostname            = NULL;
+    gint64                         carrier_timeout_sec = 0;
+
+    connections = _parse(ARGV, &hostname, &carrier_timeout_sec);
+    g_assert_cmpint(g_hash_table_size(connections), ==, 2);
+    g_assert_cmpstr(hostname, ==, "hostname1.example.com");
+    g_assert_cmpint(carrier_timeout_sec, ==, 0);
+
+    connection = g_hash_table_lookup(connections, "eth3");
+    nmtst_assert_connection_verifies_without_normalization(connection);
+    g_assert_cmpstr(nm_connection_get_id(connection), ==, "eth3");
+
+    s_con = nm_connection_get_setting_connection(connection);
+    g_assert(s_con);
+    g_assert_cmpint(nm_setting_connection_get_wait_device_timeout(s_con), ==, -1);
+
+    s_ip4 = nm_connection_get_setting_ip4_config(connection);
+    g_assert(s_ip4);
+    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4),
+                    ==,
+                    NM_SETTING_IP4_CONFIG_METHOD_MANUAL);
+    g_assert(!nm_setting_ip_config_get_ignore_auto_dns(s_ip4));
+    g_assert_cmpint(nm_setting_ip_config_get_num_dns(s_ip4), ==, 1);
+    g_assert_cmpstr(nm_setting_ip_config_get_dns(s_ip4, 0), ==, "192.0.2.53");
+    g_assert_cmpint(nm_setting_ip_config_get_num_routes(s_ip4), ==, 0);
+    g_assert_cmpint(nm_setting_ip_config_get_num_addresses(s_ip4), ==, 1);
+    ip_addr = nm_setting_ip_config_get_address(s_ip4, 0);
+    g_assert(ip_addr);
+    g_assert_cmpstr(nm_ip_address_get_address(ip_addr), ==, "192.0.2.2");
+    g_assert_cmpint(nm_ip_address_get_prefix(ip_addr), ==, 24);
+    g_assert_cmpstr(nm_setting_ip_config_get_gateway(s_ip4), ==, "192.0.2.1");
+    g_assert_cmpstr(nm_setting_ip_config_get_dhcp_hostname(s_ip4), ==, "hostname0.example.com");
+    g_assert_cmpint(nm_setting_ip_config_get_required_timeout(s_ip4), ==, -1);
+
+    s_ip6 = nm_connection_get_setting_ip6_config(connection);
+    g_assert(s_ip6);
+    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6),
+                    ==,
+                    NM_SETTING_IP6_CONFIG_METHOD_DISABLED);
+    g_assert(nm_setting_ip_config_get_may_fail(s_ip6));
+    g_assert_cmpint(nm_setting_ip_config_get_required_timeout(s_ip6), ==, -1);
+
+    connection = g_hash_table_lookup(connections, "eth4");
+    nmtst_assert_connection_verifies_without_normalization(connection);
+    g_assert_cmpstr(nm_connection_get_id(connection), ==, "eth4");
+
+    s_ip4 = nm_connection_get_setting_ip4_config(connection);
+    g_assert(s_ip4);
+    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4),
+                    ==,
+                    NM_SETTING_IP4_CONFIG_METHOD_MANUAL);
+    g_assert(!nm_setting_ip_config_get_ignore_auto_dns(s_ip4));
+    g_assert_cmpint(nm_setting_ip_config_get_num_dns(s_ip4), ==, 0);
+    g_assert_cmpint(nm_setting_ip_config_get_num_routes(s_ip4), ==, 0);
+    g_assert_cmpint(nm_setting_ip_config_get_num_addresses(s_ip4), ==, 1);
+    ip_addr = nm_setting_ip_config_get_address(s_ip4, 0);
+    g_assert(ip_addr);
+    g_assert_cmpstr(nm_ip_address_get_address(ip_addr), ==, "203.0.113.2");
+    g_assert_cmpint(nm_ip_address_get_prefix(ip_addr), ==, 26);
+    g_assert_cmpstr(nm_setting_ip_config_get_gateway(s_ip4), ==, "203.0.113.1");
+    g_assert_cmpstr(nm_setting_ip_config_get_dhcp_hostname(s_ip4), ==, "hostname1.example.com");
+
+    s_ip6 = nm_connection_get_setting_ip6_config(connection);
+    g_assert(s_ip6);
+    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_AUTO);
+    g_assert(nm_setting_ip_config_get_may_fail(s_ip6));
+}
+
+static void
+test_if_ip4_manual_no_dev(void)
+{
+    const char *const *  ARGV = NM_MAKE_STRV("ip=192.0.2.2::192.0.2.1:24:::", "=foo");
+    NMConnection *       connection;
+    NMSettingConnection *s_con;
+    NMSettingIPConfig *  s_ip4;
+    NMSettingIPConfig *  s_ip6;
+    NMIPAddress *        ip_addr;
+
+    connection = _parse_con(ARGV, "default_connection");
+    g_assert_cmpstr(nm_connection_get_id(connection), ==, "Wired Connection");
+
+    s_con = nm_connection_get_setting_connection(connection);
+    g_assert(s_con);
+    g_assert_cmpint(nm_setting_connection_get_wait_device_timeout(s_con), ==, -1);
+    g_assert_cmpint(nm_setting_connection_get_multi_connect(s_con),
+                    ==,
+                    NM_CONNECTION_MULTI_CONNECT_SINGLE);
+
+    s_ip4 = nm_connection_get_setting_ip4_config(connection);
+    g_assert(s_ip4);
+    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4),
+                    ==,
+                    NM_SETTING_IP4_CONFIG_METHOD_MANUAL);
+    g_assert(!nm_setting_ip_config_get_ignore_auto_dns(s_ip4));
+    g_assert_cmpint(nm_setting_ip_config_get_num_routes(s_ip4), ==, 0);
+    g_assert_cmpint(nm_setting_ip_config_get_num_addresses(s_ip4), ==, 1);
+    ip_addr = nm_setting_ip_config_get_address(s_ip4, 0);
+    g_assert(ip_addr);
+    g_assert_cmpstr(nm_ip_address_get_address(ip_addr), ==, "192.0.2.2");
+    g_assert_cmpint(nm_ip_address_get_prefix(ip_addr), ==, 24);
+    g_assert_cmpstr(nm_setting_ip_config_get_gateway(s_ip4), ==, "192.0.2.1");
+
+    s_ip6 = nm_connection_get_setting_ip6_config(connection);
+    g_assert(s_ip6);
+    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_AUTO);
+    g_assert(nm_setting_ip_config_get_may_fail(s_ip6));
+}
+
+static void
+test_if_ip6_manual(void)
+{
+    gs_unref_hashtable GHashTable *connections = NULL;
+    const char *const *            ARGV = NM_MAKE_STRV("ip=[2001:0db8::02]/64::[2001:0db8::01]::"
+                                           "hostname0.example.com:eth4::[2001:0db8::53]");
+    NMConnection *                 connection;
+    NMSettingIPConfig *            s_ip6;
+    NMIPAddress *                  ip_addr;
+    gs_free char *                 hostname            = NULL;
+    gint64                         carrier_timeout_sec = 0;
+
+    connections = _parse(ARGV, &hostname, &carrier_timeout_sec);
+    g_assert_cmpint(g_hash_table_size(connections), ==, 1);
+    g_assert_cmpstr(hostname, ==, "hostname0.example.com");
+    g_assert_cmpint(carrier_timeout_sec, ==, 0);
+
+    connection = g_hash_table_lookup(connections, "eth4");
+    nmtst_assert_connection_verifies_without_normalization(connection);
+    g_assert_cmpstr(nm_connection_get_id(connection), ==, "eth4");
+
+    s_ip6 = nm_connection_get_setting_ip6_config(connection);
+    g_assert(s_ip6);
+    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6),
+                    ==,
+                    NM_SETTING_IP6_CONFIG_METHOD_MANUAL);
+    g_assert(!nm_setting_ip_config_get_ignore_auto_dns(s_ip6));
+    g_assert_cmpint(nm_setting_ip_config_get_num_dns(s_ip6), ==, 1);
+    g_assert_cmpstr(nm_setting_ip_config_get_dns(s_ip6, 0), ==, "2001:db8::53");
+    g_assert_cmpint(nm_setting_ip_config_get_num_routes(s_ip6), ==, 0);
+    g_assert_cmpint(nm_setting_ip_config_get_num_addresses(s_ip6), ==, 1);
+    ip_addr = nm_setting_ip_config_get_address(s_ip6, 0);
+    g_assert(ip_addr);
+    g_assert_cmpstr(nm_ip_address_get_address(ip_addr), ==, "2001:db8::2");
+    g_assert_cmpint(nm_ip_address_get_prefix(ip_addr), ==, 64);
+    g_assert_cmpstr(nm_setting_ip_config_get_gateway(s_ip6), ==, "2001:db8::1");
+    g_assert_cmpstr(nm_setting_ip_config_get_dhcp_hostname(s_ip6), ==, "hostname0.example.com");
+}
+
+static void
+test_if_off(void)
+{
+    gs_unref_hashtable GHashTable *connections = NULL;
+    const char *const *            ARGV        = NM_MAKE_STRV("ip=off",
+                                           "ip=ens3:off",
+                                           "ip=10.0.0.8:::::ens4:off",
+                                           "ip=[2001:DB8::8]:::::ens5:off");
+    NMConnection *                 connection;
+    NMSettingIPConfig *            s_ip4;
+    NMSettingIPConfig *            s_ip6;
+    struct {
+        const char name[32];
+        const char ipv4_method[32];
+        const char ipv6_method[32];
+    } conn_expected[] = {
+        {"default_connection",
+         NM_SETTING_IP4_CONFIG_METHOD_DISABLED,
+         NM_SETTING_IP6_CONFIG_METHOD_DISABLED},
+        {"ens3", NM_SETTING_IP4_CONFIG_METHOD_DISABLED, NM_SETTING_IP6_CONFIG_METHOD_DISABLED},
+        {"ens4", NM_SETTING_IP4_CONFIG_METHOD_MANUAL, NM_SETTING_IP6_CONFIG_METHOD_DISABLED},
+        {"ens5", NM_SETTING_IP4_CONFIG_METHOD_DISABLED, NM_SETTING_IP6_CONFIG_METHOD_MANUAL},
+    };
+    guint i;
+
+    connections = _parse_cons(ARGV);
+    g_assert_cmpint(g_hash_table_size(connections), ==, G_N_ELEMENTS(conn_expected));
+
+    for (i = 0; i < G_N_ELEMENTS(conn_expected); i++) {
+        connection = g_hash_table_lookup(connections, conn_expected[i].name);
+        nmtst_assert_connection_verifies_without_normalization(connection);
+
+        s_ip4 = nm_connection_get_setting_ip4_config(connection);
+        g_assert(s_ip4);
+        g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4), ==, conn_expected[i].ipv4_method);
+
+        s_ip6 = nm_connection_get_setting_ip6_config(connection);
+        g_assert(s_ip6);
+        g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6), ==, conn_expected[i].ipv6_method);
+    }
+}
+
+static void
+test_if_mac_ifname(void)
+{
+    gs_unref_hashtable GHashTable *connections = NULL;
+    const char *const *            ARGV = NM_MAKE_STRV("ip=[2001:0db8::42]/64::[2001:0db8::01]::"
+                                           "hostname0:00-11-22-33-44-55::[2001:0db8::53]");
+    NMConnection *                 connection;
+    NMSettingIPConfig *            s_ip6;
+    NMSettingWired *               s_wired;
+    NMIPAddress *                  ip_addr;
+    gs_free char *                 hostname            = NULL;
+    gint64                         carrier_timeout_sec = 0;
+
+    connections = _parse(ARGV, &hostname, &carrier_timeout_sec);
+    g_assert_cmpint(g_hash_table_size(connections), ==, 1);
+    g_assert_cmpstr(hostname, ==, "hostname0");
+    g_assert_cmpint(carrier_timeout_sec, ==, 0);
+
+    connection = g_hash_table_lookup(connections, "00:11:22:33:44:55");
+    nmtst_assert_connection_verifies_without_normalization(connection);
+    g_assert_cmpstr(nm_connection_get_id(connection), ==, "00:11:22:33:44:55");
+    g_assert_cmpstr(nm_connection_get_interface_name(connection), ==, NULL);
+
+    s_wired = nm_connection_get_setting_wired(connection);
+    g_assert(s_wired);
+    g_assert_cmpstr(nm_setting_wired_get_mac_address(s_wired), ==, "00:11:22:33:44:55");
+
+    s_ip6 = nm_connection_get_setting_ip6_config(connection);
+    g_assert(s_ip6);
+    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6),
+                    ==,
+                    NM_SETTING_IP6_CONFIG_METHOD_MANUAL);
+    g_assert(!nm_setting_ip_config_get_ignore_auto_dns(s_ip6));
+    g_assert_cmpint(nm_setting_ip_config_get_num_dns(s_ip6), ==, 1);
+    g_assert_cmpstr(nm_setting_ip_config_get_dns(s_ip6, 0), ==, "2001:db8::53");
+    g_assert_cmpint(nm_setting_ip_config_get_num_routes(s_ip6), ==, 0);
+    g_assert_cmpint(nm_setting_ip_config_get_num_addresses(s_ip6), ==, 1);
+    ip_addr = nm_setting_ip_config_get_address(s_ip6, 0);
+    g_assert(ip_addr);
+    g_assert_cmpstr(nm_ip_address_get_address(ip_addr), ==, "2001:db8::42");
+    g_assert_cmpint(nm_ip_address_get_prefix(ip_addr), ==, 64);
+    g_assert_cmpstr(nm_setting_ip_config_get_gateway(s_ip6), ==, "2001:db8::1");
+    g_assert_cmpstr(nm_setting_ip_config_get_dhcp_hostname(s_ip6), ==, "hostname0");
+}
+
+static void
+test_multiple_merge(void)
+{
+    const char *const *ARGV =
+        NM_MAKE_STRV("ip=192.0.2.2/16:::::eth0", "ip=[2001:db8::2]:::56::eth0");
+    gs_unref_object NMConnection *connection = NULL;
+    NMSettingConnection *         s_con;
+    NMSettingWired *              s_wired;
+    NMSettingIPConfig *           s_ip4;
+    NMSettingIPConfig *           s_ip6;
+    NMIPAddress *                 ip_addr;
+
+    connection = _parse_con(ARGV, "eth0");
+
+    g_assert_cmpstr(nm_connection_get_id(connection), ==, "eth0");
+
+    s_con = nm_connection_get_setting_connection(connection);
+    g_assert(s_con);
+    g_assert_cmpint(nm_setting_connection_get_wait_device_timeout(s_con), ==, -1);
+
+    s_wired = nm_connection_get_setting_wired(connection);
+    g_assert(s_wired);
+
+    s_ip4 = nm_connection_get_setting_ip4_config(connection);
+    g_assert(s_ip4);
+    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4),
+                    ==,
+                    NM_SETTING_IP4_CONFIG_METHOD_MANUAL);
+    g_assert(!nm_setting_ip_config_get_ignore_auto_dns(s_ip4));
+    g_assert_cmpint(nm_setting_ip_config_get_num_addresses(s_ip4), ==, 1);
+    ip_addr = nm_setting_ip_config_get_address(s_ip4, 0);
+    g_assert(ip_addr);
+    g_assert_cmpstr(nm_ip_address_get_address(ip_addr), ==, "192.0.2.2");
+    g_assert_cmpint(nm_ip_address_get_prefix(ip_addr), ==, 16);
+
+    s_ip6 = nm_connection_get_setting_ip6_config(connection);
+    g_assert(s_ip6);
+    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6),
+                    ==,
+                    NM_SETTING_IP6_CONFIG_METHOD_MANUAL);
+    g_assert(!nm_setting_ip_config_get_ignore_auto_dns(s_ip6));
+    g_assert_cmpint(nm_setting_ip_config_get_num_addresses(s_ip6), ==, 1);
+    ip_addr = nm_setting_ip_config_get_address(s_ip6, 0);
+    g_assert(ip_addr);
+    g_assert_cmpstr(nm_ip_address_get_address(ip_addr), ==, "2001:db8::2");
+    g_assert_cmpint(nm_ip_address_get_prefix(ip_addr), ==, 56);
+}
+
+static void
+test_multiple_bootdev(void)
+{
+    gs_unref_hashtable GHashTable *connections = NULL;
+
+    const char *const *ARGV = NM_MAKE_STRV("nameserver=1.2.3.4",
+                                           "ip=eth3:auto6",
+                                           "ip=eth4:dhcp",
+                                           "ip=eth5:link6",
+                                           "bootdev=eth4");
+
+    NMConnection *       connection;
+    NMSettingConnection *s_con;
+    NMSettingIPConfig *  s_ip4;
+    NMSettingIPConfig *  s_ip6;
+
+    connections = _parse_cons(ARGV);
+    g_assert_cmpint(g_hash_table_size(connections), ==, 3);
+
+    connection = g_hash_table_lookup(connections, "eth3");
+    g_assert(connection);
+    s_con = nm_connection_get_setting_connection(connection);
+    g_assert(s_con);
+    g_assert_cmpint(nm_setting_connection_get_wait_device_timeout(s_con), ==, -1);
+    s_ip6 = nm_connection_get_setting_ip6_config(connection);
+    g_assert(s_ip6);
+    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_AUTO);
+
+    connection = g_hash_table_lookup(connections, "eth4");
+    g_assert(connection);
+    s_con = nm_connection_get_setting_connection(connection);
+    g_assert(s_con);
+    g_assert_cmpint(nm_setting_connection_get_wait_device_timeout(s_con),
+                    ==,
+                    NMI_WAIT_DEVICE_TIMEOUT_MSEC);
+    s_ip4 = nm_connection_get_setting_ip4_config(connection);
+    g_assert(s_ip4);
+    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_AUTO);
+    g_assert_cmpint(nm_setting_ip_config_get_num_dns(s_ip4), ==, 1);
+    g_assert_cmpstr(nm_setting_ip_config_get_dns(s_ip4, 0), ==, "1.2.3.4");
+
+    connection = g_hash_table_lookup(connections, "eth5");
+    g_assert(connection);
+    s_con = nm_connection_get_setting_connection(connection);
+    g_assert(s_con);
+    g_assert_cmpint(nm_setting_connection_get_wait_device_timeout(s_con), ==, -1);
+    s_ip6 = nm_connection_get_setting_ip6_config(connection);
+    g_assert(s_ip6);
+    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6),
+                    ==,
+                    NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL);
+}
+
+static void
+test_bootdev(void)
+{
+    gs_unref_hashtable GHashTable *connections = NULL;
+    const char *const *            ARGV        = NM_MAKE_STRV("vlan=vlan2:ens5", "bootdev=ens3");
+    NMConnection *                 connection;
+    NMSettingConnection *          s_con;
+
+    connections = _parse_cons(ARGV);
+    g_assert_cmpint(g_hash_table_size(connections), ==, 3);
+
+    connection = g_hash_table_lookup(connections, "ens3");
+    nmtst_assert_connection_verifies_without_normalization(connection);
+
+    s_con = nm_connection_get_setting_connection(connection);
+    g_assert(s_con);
+    g_assert_cmpstr(nm_setting_connection_get_connection_type(s_con),
+                    ==,
+                    NM_SETTING_WIRED_SETTING_NAME);
+    g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "ens3");
+    g_assert_cmpstr(nm_setting_connection_get_interface_name(s_con), ==, "ens3");
+    g_assert_cmpint(nm_setting_connection_get_wait_device_timeout(s_con),
+                    ==,
+                    NMI_WAIT_DEVICE_TIMEOUT_MSEC);
+
+    connection = g_hash_table_lookup(connections, "vlan2");
+    nmtst_assert_connection_verifies_without_normalization(connection);
+
+    s_con = nm_connection_get_setting_connection(connection);
+    g_assert(s_con);
+    g_assert_cmpstr(nm_setting_connection_get_connection_type(s_con),
+                    ==,
+                    NM_SETTING_VLAN_SETTING_NAME);
+    g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "vlan2");
+    g_assert_cmpstr(nm_setting_connection_get_interface_name(s_con), ==, "vlan2");
+
+    connection = g_hash_table_lookup(connections, "ens5");
+    nmtst_assert_connection_verifies_without_normalization(connection);
+
+    s_con = nm_connection_get_setting_connection(connection);
+    g_assert(s_con);
+    g_assert_cmpstr(nm_setting_connection_get_connection_type(s_con),
+                    ==,
+                    NM_SETTING_WIRED_SETTING_NAME);
+    g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "ens5");
+    g_assert_cmpstr(nm_setting_connection_get_interface_name(s_con), ==, "ens5");
+}
+
+static void
+test_some_more(void)
+{
+    gs_unref_hashtable GHashTable *connections = NULL;
+    const char *const *            ARGV        = NM_MAKE_STRV("bootdev=eth1",
+                                           "hail",
+                                           "nameserver=[2001:DB8:3::53]",
+                                           "satan",
+                                           "nameserver=192.0.2.53",
+                                           "worship",
+                                           "doom",
+                                           "rd.peerdns=0",
+                                           "rd.route=[2001:DB8:3::/48]:[2001:DB8:2::1]:ens10");
+    NMConnection *                 connection;
+    NMSettingConnection *          s_con;
+    NMSettingWired *               s_wired;
+    NMSettingIPConfig *            s_ip4;
+    NMSettingIPConfig *            s_ip6;
+    NMIPRoute *                    ip_route;
+
+    connections = _parse_cons(ARGV);
+    g_assert_cmpint(g_hash_table_size(connections), ==, 2);
+
+    connection = g_hash_table_lookup(connections, "eth1");
+    nmtst_assert_connection_verifies_without_normalization(connection);
+
+    s_con = nm_connection_get_setting_connection(connection);
+    g_assert(s_con);
+    g_assert_cmpstr(nm_setting_connection_get_connection_type(s_con),
+                    ==,
+                    NM_SETTING_WIRED_SETTING_NAME);
+    g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "eth1");
+    g_assert_cmpstr(nm_setting_connection_get_interface_name(s_con), ==, "eth1");
+    g_assert_cmpint(nm_setting_connection_get_multi_connect(s_con),
+                    ==,
+                    NM_CONNECTION_MULTI_CONNECT_SINGLE);
+
+    s_wired = nm_connection_get_setting_wired(connection);
+    g_assert(s_wired);
+
+    s_ip4 = nm_connection_get_setting_ip4_config(connection);
+    g_assert(s_ip4);
+    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_AUTO);
+    g_assert(nm_setting_ip_config_get_ignore_auto_dns(s_ip4));
+    g_assert_cmpint(nm_setting_ip_config_get_num_addresses(s_ip4), ==, 0);
+    g_assert(!nm_setting_ip_config_get_gateway(s_ip4));
+    g_assert_cmpint(nm_setting_ip_config_get_num_dns(s_ip4), ==, 1);
+    g_assert_cmpstr(nm_setting_ip_config_get_dns(s_ip4, 0), ==, "192.0.2.53");
+
+    s_ip6 = nm_connection_get_setting_ip6_config(connection);
+    g_assert(s_ip6);
+    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_AUTO);
+    g_assert(nm_setting_ip_config_get_ignore_auto_dns(s_ip6));
+    g_assert_cmpint(nm_setting_ip_config_get_num_dns(s_ip6), ==, 1);
+    g_assert(!nm_setting_ip_config_get_gateway(s_ip6));
+    g_assert_cmpstr(nm_setting_ip_config_get_dns(s_ip6, 0), ==, "2001:db8:3::53");
+
+    connection = g_hash_table_lookup(connections, "ens10");
+    nmtst_assert_connection_verifies_without_normalization(connection);
+
+    s_con = nm_connection_get_setting_connection(connection);
+    g_assert(s_con);
+    g_assert_cmpstr(nm_setting_connection_get_connection_type(s_con),
+                    ==,
+                    NM_SETTING_WIRED_SETTING_NAME);
+    g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "ens10");
+    g_assert_cmpstr(nm_setting_connection_get_interface_name(s_con), ==, "ens10");
+    g_assert_cmpint(nm_setting_connection_get_multi_connect(s_con),
+                    ==,
+                    NM_CONNECTION_MULTI_CONNECT_SINGLE);
+
+    s_wired = nm_connection_get_setting_wired(connection);
+    g_assert(s_wired);
+    g_assert(!nm_setting_wired_get_mac_address(s_wired));
+
+    s_ip6 = nm_connection_get_setting_ip6_config(connection);
+    g_assert(s_ip6);
+    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_AUTO);
+    g_assert_cmpint(nm_setting_ip_config_get_num_dns(s_ip6), ==, 1);
+    g_assert_cmpstr(nm_setting_ip_config_get_dns(s_ip6, 0), ==, "2001:db8:3::53");
+    g_assert_cmpint(nm_setting_ip_config_get_num_routes(s_ip6), ==, 1);
+    g_assert(!nm_setting_ip_config_get_gateway(s_ip6));
+    ip_route = nm_setting_ip_config_get_route(s_ip6, 0);
+    g_assert_cmpstr(nm_ip_route_get_dest(ip_route), ==, "2001:db8:3::");
+    g_assert_cmpint(nm_ip_route_get_family(ip_route), ==, AF_INET6);
+    g_assert_cmpint(nm_ip_route_get_metric(ip_route), ==, -1);
+    g_assert_cmpstr(nm_ip_route_get_next_hop(ip_route), ==, "2001:db8:2::1");
+    g_assert_cmpint(nm_ip_route_get_prefix(ip_route), ==, 48);
+}
+
+static void
+test_bond(void)
+{
+    gs_unref_hashtable GHashTable *connections = NULL;
+    const char *const *            ARGV        = NM_MAKE_STRV("rd.route=192.0.2.53::bong0",
+                                           "bond=bong0:eth0,eth1:mode=balance-rr:9000",
+                                           "nameserver=203.0.113.53");
+    NMConnection *                 connection;
+    NMSettingConnection *          s_con;
+    NMSettingIPConfig *            s_ip4;
+    NMSettingIPConfig *            s_ip6;
+    NMSettingBond *                s_bond;
+    NMSettingWired *               s_wired;
+    NMIPRoute *                    ip_route;
+    const char *                   master_uuid;
+
+    connections = _parse_cons(ARGV);
+    g_assert_cmpint(g_hash_table_size(connections), ==, 3);
+
+    connection = g_hash_table_lookup(connections, "bong0");
+    nmtst_assert_connection_verifies_without_normalization(connection);
+    g_assert_cmpstr(nm_connection_get_connection_type(connection),
+                    ==,
+                    NM_SETTING_BOND_SETTING_NAME);
+    g_assert_cmpstr(nm_connection_get_id(connection), ==, "bong0");
+    master_uuid = nm_connection_get_uuid(connection);
+    g_assert(master_uuid);
+
+    s_wired = nm_connection_get_setting_wired(connection);
+    g_assert(s_wired);
+    g_assert_cmpint(nm_setting_wired_get_mtu(s_wired), ==, 9000);
+
+    s_ip4 = nm_connection_get_setting_ip4_config(connection);
+    g_assert(s_ip4);
+    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_AUTO);
+    g_assert(!nm_setting_ip_config_get_ignore_auto_dns(s_ip4));
+    g_assert_cmpint(nm_setting_ip_config_get_num_dns(s_ip4), ==, 1);
+    g_assert_cmpstr(nm_setting_ip_config_get_dns(s_ip4, 0), ==, "203.0.113.53");
+    g_assert(!nm_setting_ip_config_get_gateway(s_ip4));
+    g_assert_cmpint(nm_setting_ip_config_get_num_routes(s_ip4), ==, 1);
+    ip_route = nm_setting_ip_config_get_route(s_ip4, 0);
+    g_assert_cmpstr(nm_ip_route_get_dest(ip_route), ==, "192.0.2.53");
+    g_assert_cmpint(nm_ip_route_get_family(ip_route), ==, AF_INET);
+    g_assert_cmpint(nm_ip_route_get_metric(ip_route), ==, -1);
+    g_assert(!nm_ip_route_get_next_hop(ip_route));
+    g_assert_cmpint(nm_ip_route_get_prefix(ip_route), ==, 32);
+
+    s_ip6 = nm_connection_get_setting_ip6_config(connection);
+    g_assert(s_ip6);
+    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_AUTO);
+    g_assert(!nm_setting_ip_config_get_ignore_auto_dns(s_ip6));
+    g_assert_cmpint(nm_setting_ip_config_get_num_dns(s_ip6), ==, 0);
+    g_assert(!nm_setting_ip_config_get_gateway(s_ip6));
+    g_assert_cmpint(nm_setting_ip_config_get_num_routes(s_ip6), ==, 0);
+
+    s_bond = nm_connection_get_setting_bond(connection);
+    g_assert(s_bond);
+    g_assert_cmpint(nm_setting_bond_get_num_options(s_bond), ==, 1);
+    g_assert_cmpstr(nm_setting_bond_get_option_by_name(s_bond, "mode"), ==, "balance-rr");
+
+    connection = g_hash_table_lookup(connections, "eth0");
+    nmtst_assert_connection_verifies_without_normalization(connection);
+    g_assert_cmpstr(nm_connection_get_id(connection), ==, "eth0");
+
+    s_con = nm_connection_get_setting_connection(connection);
+    g_assert(s_con);
+    g_assert_cmpstr(nm_setting_connection_get_connection_type(s_con),
+                    ==,
+                    NM_SETTING_WIRED_SETTING_NAME);
+    g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "eth0");
+    g_assert_cmpstr(nm_setting_connection_get_slave_type(s_con), ==, NM_SETTING_BOND_SETTING_NAME);
+    g_assert_cmpstr(nm_setting_connection_get_master(s_con), ==, master_uuid);
+    g_assert_cmpint(nm_setting_connection_get_multi_connect(s_con),
+                    ==,
+                    NM_CONNECTION_MULTI_CONNECT_SINGLE);
+
+    connection = g_hash_table_lookup(connections, "eth1");
+    nmtst_assert_connection_verifies_without_normalization(connection);
+    g_assert_cmpstr(nm_connection_get_id(connection), ==, "eth1");
+
+    s_con = nm_connection_get_setting_connection(connection);
+    g_assert(s_con);
+    g_assert_cmpstr(nm_setting_connection_get_connection_type(s_con),
+                    ==,
+                    NM_SETTING_WIRED_SETTING_NAME);
+    g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "eth1");
+    g_assert_cmpstr(nm_setting_connection_get_slave_type(s_con), ==, NM_SETTING_BOND_SETTING_NAME);
+    g_assert_cmpstr(nm_setting_connection_get_master(s_con), ==, master_uuid);
+    g_assert_cmpint(nm_setting_connection_get_multi_connect(s_con),
+                    ==,
+                    NM_CONNECTION_MULTI_CONNECT_SINGLE);
+}
+
+static void
+test_bond_ip(void)
+{
+    gs_unref_hashtable GHashTable *connections = NULL;
+    const char *const *            ARGV =
+        NM_MAKE_STRV("bond=bond0:eth0,eth1",
+                     "ip=192.168.1.1::192.168.1.254:24::bond0:none:1480:01:02:03:04:05:06",
+                     "nameserver=4.8.15.16");
+    NMConnection *       connection;
+    NMSettingConnection *s_con;
+    NMSettingIPConfig *  s_ip4;
+    NMSettingIPConfig *  s_ip6;
+    NMSettingWired *     s_wired;
+    NMSettingBond *      s_bond;
+    NMIPAddress *        ip_addr;
+    const char *         master_uuid;
+
+    connections = _parse_cons(ARGV);
+    g_assert_cmpint(g_hash_table_size(connections), ==, 3);
+
+    connection = g_hash_table_lookup(connections, "bond0");
+    nmtst_assert_connection_verifies_without_normalization(connection);
+    g_assert_cmpstr(nm_connection_get_connection_type(connection),
+                    ==,
+                    NM_SETTING_BOND_SETTING_NAME);
+    g_assert_cmpstr(nm_connection_get_id(connection), ==, "bond0");
+    master_uuid = nm_connection_get_uuid(connection);
+    g_assert(master_uuid);
+
+    s_wired = nm_connection_get_setting_wired(connection);
+    g_assert(s_wired);
+    g_assert_cmpint(nm_setting_wired_get_mtu(s_wired), ==, 1480);
+    g_assert_cmpstr(nm_setting_wired_get_cloned_mac_address(s_wired), ==, "01:02:03:04:05:06");
+
+    s_ip4 = nm_connection_get_setting_ip4_config(connection);
+    g_assert(s_ip4);
+    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4),
+                    ==,
+                    NM_SETTING_IP4_CONFIG_METHOD_MANUAL);
+    g_assert_cmpint(nm_setting_ip_config_get_num_addresses(s_ip4), ==, 1);
+    ip_addr = nm_setting_ip_config_get_address(s_ip4, 0);
+    g_assert(ip_addr);
+    g_assert_cmpstr(nm_ip_address_get_address(ip_addr), ==, "192.168.1.1");
+    g_assert_cmpint(nm_ip_address_get_prefix(ip_addr), ==, 24);
+    g_assert_cmpstr(nm_setting_ip_config_get_gateway(s_ip4), ==, "192.168.1.254");
+    g_assert_cmpint(nm_setting_ip_config_get_num_dns(s_ip4), ==, 1);
+    g_assert_cmpstr(nm_setting_ip_config_get_dns(s_ip4, 0), ==, "4.8.15.16");
+    g_assert_cmpint(nm_setting_ip_config_get_num_routes(s_ip4), ==, 0);
+
+    s_ip6 = nm_connection_get_setting_ip6_config(connection);
+    g_assert(s_ip6);
+    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6),
+                    ==,
+                    NM_SETTING_IP6_CONFIG_METHOD_DISABLED);
+    g_assert(!nm_setting_ip_config_get_ignore_auto_dns(s_ip6));
+    g_assert_cmpint(nm_setting_ip_config_get_num_dns(s_ip6), ==, 0);
+    g_assert(!nm_setting_ip_config_get_gateway(s_ip6));
+    g_assert_cmpint(nm_setting_ip_config_get_num_routes(s_ip6), ==, 0);
+
+    s_bond = nm_connection_get_setting_bond(connection);
+    g_assert(s_bond);
+    g_assert_cmpint(nm_setting_bond_get_num_options(s_bond), ==, 1);
+    g_assert_cmpstr(nm_setting_bond_get_option_by_name(s_bond, "mode"), ==, "balance-rr");
+
+    connection = g_hash_table_lookup(connections, "eth0");
+    nmtst_assert_connection_verifies_without_normalization(connection);
+    g_assert_cmpstr(nm_connection_get_id(connection), ==, "eth0");
+
+    s_con = nm_connection_get_setting_connection(connection);
+    g_assert(s_con);
+    g_assert_cmpstr(nm_setting_connection_get_connection_type(s_con),
+                    ==,
+                    NM_SETTING_WIRED_SETTING_NAME);
+    g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "eth0");
+    g_assert_cmpstr(nm_setting_connection_get_slave_type(s_con), ==, NM_SETTING_BOND_SETTING_NAME);
+    g_assert_cmpstr(nm_setting_connection_get_master(s_con), ==, master_uuid);
+    g_assert_cmpint(nm_setting_connection_get_multi_connect(s_con),
+                    ==,
+                    NM_CONNECTION_MULTI_CONNECT_SINGLE);
+
+    connection = g_hash_table_lookup(connections, "eth1");
+    nmtst_assert_connection_verifies_without_normalization(connection);
+    g_assert_cmpstr(nm_connection_get_id(connection), ==, "eth1");
+
+    s_con = nm_connection_get_setting_connection(connection);
+    g_assert(s_con);
+    g_assert_cmpstr(nm_setting_connection_get_connection_type(s_con),
+                    ==,
+                    NM_SETTING_WIRED_SETTING_NAME);
+    g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "eth1");
+    g_assert_cmpstr(nm_setting_connection_get_slave_type(s_con), ==, NM_SETTING_BOND_SETTING_NAME);
+    g_assert_cmpstr(nm_setting_connection_get_master(s_con), ==, master_uuid);
+    g_assert_cmpint(nm_setting_connection_get_multi_connect(s_con),
+                    ==,
+                    NM_CONNECTION_MULTI_CONNECT_SINGLE);
+}
+
+static void
+test_bond_default(void)
+{
+    gs_unref_hashtable GHashTable *connections = NULL;
+    const char *const *            ARGV        = NM_MAKE_STRV("bond");
+    NMConnection *                 connection;
+    NMSettingConnection *          s_con;
+    NMSettingIPConfig *            s_ip4;
+    NMSettingIPConfig *            s_ip6;
+    NMSettingBond *                s_bond;
+    const char *                   master_uuid;
+
+    connections = _parse_cons(ARGV);
+    g_assert_cmpint(g_hash_table_size(connections), ==, 2);
+
+    connection = g_hash_table_lookup(connections, "bond0");
+
+    nmtst_assert_connection_verifies_without_normalization(connection);
+    g_assert_cmpstr(nm_connection_get_connection_type(connection),
+                    ==,
+                    NM_SETTING_BOND_SETTING_NAME);
+    g_assert_cmpstr(nm_connection_get_id(connection), ==, "bond0");
+    master_uuid = nm_connection_get_uuid(connection);
+    g_assert(master_uuid);
+
+    s_ip4 = nm_connection_get_setting_ip4_config(connection);
+    g_assert(s_ip4);
+    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_AUTO);
+    g_assert(!nm_setting_ip_config_get_ignore_auto_dns(s_ip4));
+    g_assert_cmpint(nm_setting_ip_config_get_num_dns(s_ip4), ==, 0);
+    g_assert(!nm_setting_ip_config_get_gateway(s_ip4));
+    g_assert_cmpint(nm_setting_ip_config_get_num_routes(s_ip4), ==, 0);
+
+    s_ip6 = nm_connection_get_setting_ip6_config(connection);
+    g_assert(s_ip6);
+    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_AUTO);
+    g_assert(!nm_setting_ip_config_get_ignore_auto_dns(s_ip6));
+    g_assert_cmpint(nm_setting_ip_config_get_num_dns(s_ip6), ==, 0);
+    g_assert(!nm_setting_ip_config_get_gateway(s_ip6));
+    g_assert_cmpint(nm_setting_ip_config_get_num_routes(s_ip6), ==, 0);
+
+    s_bond = nm_connection_get_setting_bond(connection);
+    g_assert(s_bond);
+    g_assert_cmpint(nm_setting_bond_get_num_options(s_bond), ==, 1);
+    g_assert_cmpstr(nm_setting_bond_get_option_by_name(s_bond, "mode"), ==, "balance-rr");
+
+    connection = g_hash_table_lookup(connections, "eth0");
+    nmtst_assert_connection_verifies_without_normalization(connection);
+    g_assert_cmpstr(nm_connection_get_id(connection), ==, "eth0");
+
+    s_con = nm_connection_get_setting_connection(connection);
+    g_assert(s_con);
+    g_assert_cmpstr(nm_setting_connection_get_connection_type(s_con),
+                    ==,
+                    NM_SETTING_WIRED_SETTING_NAME);
+    g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "eth0");
+    g_assert_cmpstr(nm_setting_connection_get_slave_type(s_con), ==, NM_SETTING_BOND_SETTING_NAME);
+    g_assert_cmpstr(nm_setting_connection_get_master(s_con), ==, master_uuid);
+    g_assert_cmpint(nm_setting_connection_get_multi_connect(s_con),
+                    ==,
+                    NM_CONNECTION_MULTI_CONNECT_SINGLE);
+}
+
+static void
+test_bridge(void)
+{
+    gs_unref_hashtable GHashTable *connections = NULL;
+    const char *const *            ARGV        = NM_MAKE_STRV("bridge=bridge0:eth0,eth1",
+                                           "rd.route=192.0.2.53::bridge0",
+                                           "rd.net.timeout.dhcp=10");
+    NMConnection *                 connection;
+    NMSettingConnection *          s_con;
+    NMSettingIPConfig *            s_ip4;
+    NMSettingIPConfig *            s_ip6;
+    NMSettingBridge *              s_bridge;
+    NMIPRoute *                    ip_route;
+    const char *                   master_uuid;
+
+    connections = _parse_cons(ARGV);
+    g_assert_cmpint(g_hash_table_size(connections), ==, 3);
+
+    connection = g_hash_table_lookup(connections, "bridge0");
+    nmtst_assert_connection_verifies_without_normalization(connection);
+    g_assert_cmpstr(nm_connection_get_connection_type(connection),
+                    ==,
+                    NM_SETTING_BRIDGE_SETTING_NAME);
+    g_assert_cmpstr(nm_connection_get_id(connection), ==, "bridge0");
+    master_uuid = nm_connection_get_uuid(connection);
+    g_assert(master_uuid);
+
+    s_ip4 = nm_connection_get_setting_ip4_config(connection);
+    g_assert(s_ip4);
+    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_AUTO);
+    g_assert(!nm_setting_ip_config_get_ignore_auto_dns(s_ip4));
+    g_assert_cmpint(nm_setting_ip_config_get_num_dns(s_ip4), ==, 0);
+    g_assert(!nm_setting_ip_config_get_gateway(s_ip4));
+    g_assert_cmpint(nm_setting_ip_config_get_num_routes(s_ip4), ==, 1);
+    g_assert_cmpint(nm_setting_ip_config_get_dhcp_timeout(s_ip4), ==, 10);
+    ip_route = nm_setting_ip_config_get_route(s_ip4, 0);
+    g_assert_cmpstr(nm_ip_route_get_dest(ip_route), ==, "192.0.2.53");
+    g_assert_cmpint(nm_ip_route_get_family(ip_route), ==, AF_INET);
+    g_assert_cmpint(nm_ip_route_get_metric(ip_route), ==, -1);
+    g_assert(!nm_ip_route_get_next_hop(ip_route));
+    g_assert_cmpint(nm_ip_route_get_prefix(ip_route), ==, 32);
+    g_assert_cmpint(nm_setting_ip_config_get_required_timeout(s_ip4),
+                    ==,
+                    NMI_IP_REQUIRED_TIMEOUT_MSEC);
+
+    s_ip6 = nm_connection_get_setting_ip6_config(connection);
+    g_assert(s_ip6);
+    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_AUTO);
+    g_assert(!nm_setting_ip_config_get_ignore_auto_dns(s_ip6));
+    g_assert_cmpint(nm_setting_ip_config_get_num_dns(s_ip6), ==, 0);
+    g_assert(!nm_setting_ip_config_get_gateway(s_ip6));
+    g_assert_cmpint(nm_setting_ip_config_get_num_routes(s_ip6), ==, 0);
+    g_assert_cmpint(nm_setting_ip_config_get_dhcp_timeout(s_ip6), ==, 10);
+    g_assert_cmpint(nm_setting_ip_config_get_required_timeout(s_ip6), ==, -1);
+
+    s_bridge = nm_connection_get_setting_bridge(connection);
+    g_assert(s_bridge);
+    g_assert_cmpint(nm_setting_bridge_get_stp(s_bridge), ==, FALSE);
+
+    connection = g_hash_table_lookup(connections, "eth0");
+    nmtst_assert_connection_verifies_without_normalization(connection);
+    g_assert_cmpstr(nm_connection_get_id(connection), ==, "eth0");
+
+    s_con = nm_connection_get_setting_connection(connection);
+    g_assert(s_con);
+    g_assert_cmpstr(nm_setting_connection_get_connection_type(s_con),
+                    ==,
+                    NM_SETTING_WIRED_SETTING_NAME);
+    g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "eth0");
+    g_assert_cmpstr(nm_setting_connection_get_slave_type(s_con),
+                    ==,
+                    NM_SETTING_BRIDGE_SETTING_NAME);
+    g_assert_cmpstr(nm_setting_connection_get_master(s_con), ==, master_uuid);
+    g_assert_cmpint(nm_setting_connection_get_multi_connect(s_con),
+                    ==,
+                    NM_CONNECTION_MULTI_CONNECT_SINGLE);
+
+    connection = g_hash_table_lookup(connections, "eth1");
+    nmtst_assert_connection_verifies_without_normalization(connection);
+    g_assert_cmpstr(nm_connection_get_id(connection), ==, "eth1");
+
+    s_con = nm_connection_get_setting_connection(connection);
+    g_assert(s_con);
+    g_assert_cmpstr(nm_setting_connection_get_connection_type(s_con),
+                    ==,
+                    NM_SETTING_WIRED_SETTING_NAME);
+    g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "eth1");
+    g_assert_cmpstr(nm_setting_connection_get_slave_type(s_con),
+                    ==,
+                    NM_SETTING_BRIDGE_SETTING_NAME);
+    g_assert_cmpstr(nm_setting_connection_get_master(s_con), ==, master_uuid);
+    g_assert_cmpint(nm_setting_connection_get_multi_connect(s_con),
+                    ==,
+                    NM_CONNECTION_MULTI_CONNECT_SINGLE);
+}
+
+static void
+test_bridge_default(void)
+{
+    gs_unref_hashtable GHashTable *connections = NULL;
+    const char *const *            ARGV        = NM_MAKE_STRV("bridge");
+    NMConnection *                 connection;
+    NMSettingConnection *          s_con;
+    NMSettingIPConfig *            s_ip4;
+    NMSettingIPConfig *            s_ip6;
+    NMSettingBridge *              s_bridge;
+    const char *                   master_uuid;
+
+    connections = _parse_cons(ARGV);
+    g_assert_cmpint(g_hash_table_size(connections), ==, 2);
+
+    connection = g_hash_table_lookup(connections, "br0");
+
+    nmtst_assert_connection_verifies_without_normalization(connection);
+    g_assert_cmpstr(nm_connection_get_connection_type(connection),
+                    ==,
+                    NM_SETTING_BRIDGE_SETTING_NAME);
+    g_assert_cmpstr(nm_connection_get_id(connection), ==, "br0");
+    master_uuid = nm_connection_get_uuid(connection);
+    g_assert(master_uuid);
+
+    s_ip4 = nm_connection_get_setting_ip4_config(connection);
+    g_assert(s_ip4);
+    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_AUTO);
+    g_assert(!nm_setting_ip_config_get_ignore_auto_dns(s_ip4));
+    g_assert_cmpint(nm_setting_ip_config_get_num_dns(s_ip4), ==, 0);
+    g_assert(!nm_setting_ip_config_get_gateway(s_ip4));
+    g_assert_cmpint(nm_setting_ip_config_get_num_routes(s_ip4), ==, 0);
+
+    s_ip6 = nm_connection_get_setting_ip6_config(connection);
+    g_assert(s_ip6);
+    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_AUTO);
+    g_assert(!nm_setting_ip_config_get_ignore_auto_dns(s_ip6));
+    g_assert_cmpint(nm_setting_ip_config_get_num_dns(s_ip6), ==, 0);
+    g_assert(!nm_setting_ip_config_get_gateway(s_ip6));
+    g_assert_cmpint(nm_setting_ip_config_get_num_routes(s_ip6), ==, 0);
+
+    s_bridge = nm_connection_get_setting_bridge(connection);
+    g_assert(s_bridge);
+
+    connection = g_hash_table_lookup(connections, "eth0");
+    nmtst_assert_connection_verifies_without_normalization(connection);
+    g_assert_cmpstr(nm_connection_get_id(connection), ==, "eth0");
+
+    s_con = nm_connection_get_setting_connection(connection);
+    g_assert(s_con);
+    g_assert_cmpstr(nm_setting_connection_get_connection_type(s_con),
+                    ==,
+                    NM_SETTING_WIRED_SETTING_NAME);
+    g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "eth0");
+    g_assert_cmpstr(nm_setting_connection_get_slave_type(s_con),
+                    ==,
+                    NM_SETTING_BRIDGE_SETTING_NAME);
+    g_assert_cmpstr(nm_setting_connection_get_master(s_con), ==, master_uuid);
+    g_assert_cmpint(nm_setting_connection_get_multi_connect(s_con),
+                    ==,
+                    NM_CONNECTION_MULTI_CONNECT_SINGLE);
+}
+
+static void
+test_bridge_ip(void)
+{
+    gs_unref_hashtable GHashTable *connections = NULL;
+    const char *const *            ARGV =
+        NM_MAKE_STRV("ip=bridge123:auto:1280:00:11:22:33:CA:fe",
+                     "bridge=bridge123:eth0,eth1,eth2,eth3,eth4,eth5,eth6,eth7,eth8,eth9");
+    NMConnection *       connection;
+    NMSettingConnection *s_con;
+    NMSettingIPConfig *  s_ip4;
+    NMSettingIPConfig *  s_ip6;
+    NMSettingWired *     s_wired;
+    NMSettingBridge *    s_bridge;
+    const char *         master_uuid;
+    guint                i;
+
+    connections = _parse_cons(ARGV);
+    g_assert_cmpint(g_hash_table_size(connections), ==, 11);
+
+    connection = g_hash_table_lookup(connections, "bridge123");
+    nmtst_assert_connection_verifies_without_normalization(connection);
+    g_assert_cmpstr(nm_connection_get_connection_type(connection),
+                    ==,
+                    NM_SETTING_BRIDGE_SETTING_NAME);
+    g_assert_cmpstr(nm_connection_get_id(connection), ==, "bridge123");
+    master_uuid = nm_connection_get_uuid(connection);
+    g_assert(master_uuid);
+
+    s_wired = nm_connection_get_setting_wired(connection);
+    g_assert(s_wired);
+    g_assert_cmpint(nm_setting_wired_get_mtu(s_wired), ==, 1280);
+    g_assert_cmpstr(nm_setting_wired_get_cloned_mac_address(s_wired), ==, "00:11:22:33:CA:FE");
+
+    s_ip4 = nm_connection_get_setting_ip4_config(connection);
+    g_assert(s_ip4);
+    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_AUTO);
+
+    s_ip6 = nm_connection_get_setting_ip6_config(connection);
+    g_assert(s_ip6);
+    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_AUTO);
+
+    s_bridge = nm_connection_get_setting_bridge(connection);
+    g_assert(s_bridge);
+
+    for (i = 0; i < 10; i++) {
+        char ifname[16];
+
+        nm_sprintf_buf(ifname, "eth%u", i);
+
+        connection = g_hash_table_lookup(connections, ifname);
+        nmtst_assert_connection_verifies_without_normalization(connection);
+        g_assert_cmpstr(nm_connection_get_id(connection), ==, ifname);
+
+        s_con = nm_connection_get_setting_connection(connection);
+        g_assert(s_con);
+        g_assert_cmpstr(nm_setting_connection_get_connection_type(s_con),
+                        ==,
+                        NM_SETTING_WIRED_SETTING_NAME);
+        g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, ifname);
+        g_assert_cmpstr(nm_setting_connection_get_slave_type(s_con),
+                        ==,
+                        NM_SETTING_BRIDGE_SETTING_NAME);
+        g_assert_cmpstr(nm_setting_connection_get_master(s_con), ==, master_uuid);
+        g_assert_cmpint(nm_setting_connection_get_multi_connect(s_con),
+                        ==,
+                        NM_CONNECTION_MULTI_CONNECT_SINGLE);
+    }
+}
+
+static void
+test_team(void)
+{
+    gs_unref_hashtable GHashTable *connections = NULL;
+    const char *const *            ARGV = NM_MAKE_STRV("team=team0:eth0,eth1", "ip=team0:dhcp6");
+    NMConnection *                 connection;
+    NMSettingConnection *          s_con;
+    NMSettingIPConfig *            s_ip4;
+    NMSettingIPConfig *            s_ip6;
+    NMSettingTeam *                s_team;
+    const char *                   master_uuid;
+
+    connections = _parse_cons(ARGV);
+    g_assert_cmpint(g_hash_table_size(connections), ==, 3);
+
+    connection = g_hash_table_lookup(connections, "team0");
+    nmtst_assert_connection_verifies_without_normalization(connection);
+    g_assert_cmpstr(nm_connection_get_connection_type(connection),
+                    ==,
+                    NM_SETTING_TEAM_SETTING_NAME);
+    g_assert_cmpstr(nm_connection_get_id(connection), ==, "team0");
+    master_uuid = nm_connection_get_uuid(connection);
+    g_assert(master_uuid);
+
+    s_ip4 = nm_connection_get_setting_ip4_config(connection);
+    g_assert(s_ip4);
+    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4),
+                    ==,
+                    NM_SETTING_IP4_CONFIG_METHOD_DISABLED);
+    g_assert(!nm_setting_ip_config_get_ignore_auto_dns(s_ip4));
+    g_assert_cmpint(nm_setting_ip_config_get_num_dns(s_ip4), ==, 0);
+    g_assert(!nm_setting_ip_config_get_gateway(s_ip4));
+    g_assert_cmpint(nm_setting_ip_config_get_num_routes(s_ip4), ==, 0);
+
+    s_ip6 = nm_connection_get_setting_ip6_config(connection);
+    g_assert(s_ip6);
+    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_AUTO);
+    g_assert(!nm_setting_ip_config_get_ignore_auto_dns(s_ip6));
+    g_assert_cmpint(nm_setting_ip_config_get_num_dns(s_ip6), ==, 0);
+    g_assert(!nm_setting_ip_config_get_gateway(s_ip6));
+    g_assert_cmpint(nm_setting_ip_config_get_num_routes(s_ip6), ==, 0);
+
+    s_team = nm_connection_get_setting_team(connection);
+    g_assert(s_team);
+
+    connection = g_hash_table_lookup(connections, "eth0");
+    nmtst_assert_connection_verifies_without_normalization(connection);
+    g_assert_cmpstr(nm_connection_get_id(connection), ==, "eth0");
+
+    s_con = nm_connection_get_setting_connection(connection);
+    g_assert(s_con);
+    g_assert_cmpstr(nm_setting_connection_get_connection_type(s_con),
+                    ==,
+                    NM_SETTING_WIRED_SETTING_NAME);
+    g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "eth0");
+    g_assert_cmpstr(nm_setting_connection_get_slave_type(s_con), ==, NM_SETTING_TEAM_SETTING_NAME);
+    g_assert_cmpstr(nm_setting_connection_get_master(s_con), ==, master_uuid);
+    g_assert_cmpint(nm_setting_connection_get_multi_connect(s_con),
+                    ==,
+                    NM_CONNECTION_MULTI_CONNECT_SINGLE);
+
+    connection = g_hash_table_lookup(connections, "eth1");
+    nmtst_assert_connection_verifies_without_normalization(connection);
+    g_assert_cmpstr(nm_connection_get_id(connection), ==, "eth1");
+
+    s_con = nm_connection_get_setting_connection(connection);
+    g_assert(s_con);
+    g_assert_cmpstr(nm_setting_connection_get_connection_type(s_con),
+                    ==,
+                    NM_SETTING_WIRED_SETTING_NAME);
+    g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "eth1");
+    g_assert_cmpstr(nm_setting_connection_get_slave_type(s_con), ==, NM_SETTING_TEAM_SETTING_NAME);
+    g_assert_cmpstr(nm_setting_connection_get_master(s_con), ==, master_uuid);
+    g_assert_cmpint(nm_setting_connection_get_multi_connect(s_con),
+                    ==,
+                    NM_CONNECTION_MULTI_CONNECT_SINGLE);
+}
+
+static void
+test_vlan(void)
+{
+    const char *const *ARGV0  = NM_MAKE_STRV("ip=eth0.100:dhcp", "vlan=eth0.100:eth0");
+    const char *const *ARGV1  = NM_MAKE_STRV("vlan=eth0.100:eth0", "ip=eth0.100:dhcp");
+    const char *const *ARGV[] = {ARGV0, ARGV1};
+    guint              i;
+
+    for (i = 0; i < G_N_ELEMENTS(ARGV); i++) {
+        gs_unref_hashtable GHashTable *connections = NULL;
+        NMConnection *                 connection;
+        NMSettingIPConfig *            s_ip4;
+        NMSettingIPConfig *            s_ip6;
+        NMSettingVlan *                s_vlan;
+
+        connections = _parse_cons(ARGV[i]);
+        g_assert_cmpint(g_hash_table_size(connections), ==, 2);
+
+        /* VLAN eth0.100 */
+        connection = g_hash_table_lookup(connections, "eth0.100");
+        nmtst_assert_connection_verifies_without_normalization(connection);
+        g_assert_cmpstr(nm_connection_get_connection_type(connection),
+                        ==,
+                        NM_SETTING_VLAN_SETTING_NAME);
+        g_assert_cmpstr(nm_connection_get_id(connection), ==, "eth0.100");
+
+        s_vlan = nm_connection_get_setting_vlan(connection);
+        g_assert(s_vlan);
+        g_assert_cmpstr(nm_setting_vlan_get_parent(s_vlan), ==, "eth0");
+        g_assert_cmpint(nm_setting_vlan_get_id(s_vlan), ==, 100);
+
+        s_ip4 = nm_connection_get_setting_ip4_config(connection);
+        g_assert(s_ip4);
+        g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4),
+                        ==,
+                        NM_SETTING_IP4_CONFIG_METHOD_AUTO);
+
+        s_ip6 = nm_connection_get_setting_ip6_config(connection);
+        g_assert(s_ip6);
+        g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6),
+                        ==,
+                        NM_SETTING_IP6_CONFIG_METHOD_AUTO);
+
+        /* Ethernet eth0 */
+        connection = g_hash_table_lookup(connections, "eth0");
+        nmtst_assert_connection_verifies_without_normalization(connection);
+        g_assert_cmpstr(nm_connection_get_connection_type(connection),
+                        ==,
+                        NM_SETTING_WIRED_SETTING_NAME);
+        g_assert_cmpstr(nm_connection_get_id(connection), ==, "eth0");
+
+        s_ip4 = nm_connection_get_setting_ip4_config(connection);
+        g_assert(s_ip4);
+        g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4),
+                        ==,
+                        NM_SETTING_IP4_CONFIG_METHOD_DISABLED);
+
+        s_ip6 = nm_connection_get_setting_ip6_config(connection);
+        g_assert(s_ip6);
+        g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6),
+                        ==,
+                        NM_SETTING_IP6_CONFIG_METHOD_DISABLED);
+    }
+}
+
+static void
+test_vlan_with_dhcp_on_parent(void)
+{
+    const char *const *ARGV0  = NM_MAKE_STRV("vlan=eth0.100:eth0", "ip=eth0:dhcp");
+    const char *const *ARGV1  = NM_MAKE_STRV("ip=eth0:dhcp", "vlan=eth0.100:eth0");
+    const char *const *ARGV[] = {ARGV0, ARGV1};
+    guint              i;
+
+    for (i = 0; i < G_N_ELEMENTS(ARGV); i++) {
+        gs_unref_hashtable GHashTable *connections = NULL;
+        NMConnection *                 connection;
+        NMSettingIPConfig *            s_ip4;
+        NMSettingIPConfig *            s_ip6;
+        NMSettingVlan *                s_vlan;
+
+        connections = _parse_cons(ARGV[i]);
+        g_assert_cmpint(g_hash_table_size(connections), ==, 2);
+
+        /* VLAN eth0.100 */
+        connection = g_hash_table_lookup(connections, "eth0.100");
+        nmtst_assert_connection_verifies_without_normalization(connection);
+        g_assert_cmpstr(nm_connection_get_connection_type(connection),
+                        ==,
+                        NM_SETTING_VLAN_SETTING_NAME);
+        g_assert_cmpstr(nm_connection_get_id(connection), ==, "eth0.100");
+
+        s_ip4 = nm_connection_get_setting_ip4_config(connection);
+        g_assert(s_ip4);
+        g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4),
+                        ==,
+                        NM_SETTING_IP4_CONFIG_METHOD_AUTO);
+
+        s_ip6 = nm_connection_get_setting_ip6_config(connection);
+        g_assert(s_ip6);
+        g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6),
+                        ==,
+                        NM_SETTING_IP6_CONFIG_METHOD_AUTO);
+
+        s_vlan = nm_connection_get_setting_vlan(connection);
+        g_assert(s_vlan);
+        g_assert_cmpstr(nm_setting_vlan_get_parent(s_vlan), ==, "eth0");
+        g_assert_cmpint(nm_setting_vlan_get_id(s_vlan), ==, 100);
+
+        /* Ethernet eth0 */
+        connection = g_hash_table_lookup(connections, "eth0");
+        nmtst_assert_connection_verifies_without_normalization(connection);
+        g_assert_cmpstr(nm_connection_get_connection_type(connection),
+                        ==,
+                        NM_SETTING_WIRED_SETTING_NAME);
+        g_assert_cmpstr(nm_connection_get_id(connection), ==, "eth0");
+
+        s_ip4 = nm_connection_get_setting_ip4_config(connection);
+        g_assert(s_ip4);
+        g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4),
+                        ==,
+                        NM_SETTING_IP4_CONFIG_METHOD_AUTO);
+
+        s_ip6 = nm_connection_get_setting_ip6_config(connection);
+        g_assert(s_ip6);
+        g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6),
+                        ==,
+                        NM_SETTING_IP6_CONFIG_METHOD_AUTO);
+    }
+}
+
+static void
+test_vlan_over_bond(void)
+{
+    const char *const *ARGV0  = NM_MAKE_STRV("ip=1.2.3.4:::24::vlan1:none",
+                                            "bond=bond2:ens3,ens4:mode=active-backup",
+                                            "vlan=vlan1:bond2");
+    const char *const *ARGV1  = NM_MAKE_STRV("vlan=vlan1:bond2",
+                                            "ip=1.2.3.4:::24::vlan1:none",
+                                            "bond=bond2:ens3,ens4:mode=active-backup");
+    const char *const *ARGV2  = NM_MAKE_STRV("bond=bond2:ens3,ens4:mode=active-backup",
+                                            "ip=1.2.3.4:::24::vlan1:none",
+                                            "vlan=vlan1:bond2");
+    const char *const *ARGV[] = {ARGV0, ARGV1, ARGV2};
+    guint              i;
+
+    for (i = 0; i < G_N_ELEMENTS(ARGV); i++) {
+        gs_unref_hashtable GHashTable *connections = NULL;
+        NMConnection *                 connection;
+        NMSettingIPConfig *            s_ip4;
+        NMSettingIPConfig *            s_ip6;
+        NMSettingVlan *                s_vlan;
+
+        connections = _parse_cons(ARGV[i]);
+        g_assert_cmpint(g_hash_table_size(connections), ==, 4);
+
+        /* VLAN vlan1 */
+        connection = g_hash_table_lookup(connections, "vlan1");
+        nmtst_assert_connection_verifies_without_normalization(connection);
+        g_assert_cmpstr(nm_connection_get_connection_type(connection),
+                        ==,
+                        NM_SETTING_VLAN_SETTING_NAME);
+        g_assert_cmpstr(nm_connection_get_id(connection), ==, "vlan1");
+
+        s_ip4 = nm_connection_get_setting_ip4_config(connection);
+        g_assert(s_ip4);
+        g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4),
+                        ==,
+                        NM_SETTING_IP4_CONFIG_METHOD_MANUAL);
+
+        s_ip6 = nm_connection_get_setting_ip6_config(connection);
+        g_assert(s_ip6);
+        g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6),
+                        ==,
+                        NM_SETTING_IP6_CONFIG_METHOD_DISABLED);
+
+        s_vlan = nm_connection_get_setting_vlan(connection);
+        g_assert(s_vlan);
+        g_assert_cmpstr(nm_setting_vlan_get_parent(s_vlan), ==, "bond2");
+        g_assert_cmpint(nm_setting_vlan_get_id(s_vlan), ==, 1);
+
+        /* Bond bond2 */
+        connection = g_hash_table_lookup(connections, "bond2");
+        nmtst_assert_connection_verifies_without_normalization(connection);
+        g_assert_cmpstr(nm_connection_get_connection_type(connection),
+                        ==,
+                        NM_SETTING_BOND_SETTING_NAME);
+        g_assert_cmpstr(nm_connection_get_id(connection), ==, "bond2");
+
+        s_ip4 = nm_connection_get_setting_ip4_config(connection);
+        g_assert(s_ip4);
+        g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4),
+                        ==,
+                        NM_SETTING_IP4_CONFIG_METHOD_DISABLED);
+
+        s_ip6 = nm_connection_get_setting_ip6_config(connection);
+        g_assert(s_ip6);
+        g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6),
+                        ==,
+                        NM_SETTING_IP6_CONFIG_METHOD_DISABLED);
+
+        /* Ethernet ens3 and ens4 */
+        connection = g_hash_table_lookup(connections, "ens3");
+        g_assert(connection);
+        connection = g_hash_table_lookup(connections, "ens4");
+        g_assert(connection);
+    }
+}
+
+static void
+test_ibft_ip_dev(void)
+{
+    const char *const *  ARGV = NM_MAKE_STRV("ip=eth0:ibft");
+    NMSettingConnection *s_con;
+    gs_unref_object NMConnection *connection = NULL;
+
+    connection = _parse_con(ARGV, "eth0");
+
+    s_con = nm_connection_get_setting_connection(connection);
+    g_assert(s_con);
+    g_assert_cmpstr(nm_setting_connection_get_connection_type(s_con),
+                    ==,
+                    NM_SETTING_VLAN_SETTING_NAME);
+    g_assert_cmpstr(nm_setting_connection_get_interface_name(s_con), ==, NULL);
+}
+
+static void
+test_ibft_ip_dev_mac(void)
+{
+    const char *const *  ARGV = NM_MAKE_STRV("ip=00-53-06-66-ab-01:ibft");
+    NMSettingConnection *s_con;
+    gs_unref_object NMConnection *connection = NULL;
+
+    connection = _parse_con(ARGV, "00:53:06:66:AB:01");
+
+    s_con = nm_connection_get_setting_connection(connection);
+    g_assert(s_con);
+    g_assert_cmpstr(nm_setting_connection_get_connection_type(s_con),
+                    ==,
+                    NM_SETTING_WIRED_SETTING_NAME);
+    g_assert_cmpstr(nm_setting_connection_get_interface_name(s_con), ==, NULL);
+}
+
+static void
+_test_ibft_ip(const char *const *ARGV)
+{
+    gs_unref_hashtable GHashTable *connections = NULL;
+    NMConnection *                 connection;
+
+    connections = _parse_cons(ARGV);
+    g_assert_cmpint(g_hash_table_size(connections), ==, 2);
+
+    connection = g_hash_table_lookup(connections, "ibft0");
+    nmtst_assert_connection_verifies_without_normalization(connection);
+
+    g_assert_cmpstr(nm_connection_get_id(connection), ==, "iBFT VLAN Connection 0");
+    g_assert_cmpstr(nm_connection_get_interface_name(connection), ==, NULL);
+
+    connection = g_hash_table_lookup(connections, "ibft2");
+    nmtst_assert_connection_verifies_without_normalization(connection);
+    g_assert_cmpstr(nm_connection_get_id(connection), ==, "iBFT Connection 2");
+    g_assert_cmpstr(nm_connection_get_interface_name(connection), ==, NULL);
+}
+
+static void
+test_ibft_ip(void)
+{
+    const char *const *ARGV = NM_MAKE_STRV("ip=ibft");
+
+    _test_ibft_ip(ARGV);
+}
+
+static void
+test_ibft_rd_iscsi_ibft(void)
+{
+    const char *const *ARGV = NM_MAKE_STRV("rd.iscsi.ibft");
+
+    _test_ibft_ip(ARGV);
+}
+
+static void
+test_ignore_extra(void)
+{
+    gs_unref_hashtable GHashTable *connections = NULL;
+    const char *const *            ARGV        = NM_MAKE_STRV("blabla", "extra", "lalala");
+
+    connections = _parse_cons(ARGV);
+    g_assert_cmpint(g_hash_table_size(connections), ==, 0);
+}
+
+static void
+test_rd_znet(void)
+{
+    gs_unref_hashtable GHashTable *connections = NULL;
+    const char *const *const       ARGV =
+        NM_MAKE_STRV("ip=10.11.12.13::10.11.12.1:24:foo.example.com:enc800:none",
+                     "ip=slc600:dhcp",
+                     "rd.znet=qeth,0.0.0800,0.0.0801,0.0.0802,layer2=0,portno=1",
+                     "rd.znet=ctc,0.0.0600,0.0.0601,layer2=0,portno=0");
+    NMConnection *          connection;
+    NMSettingConnection *   s_con;
+    NMSettingWired *        s_wired;
+    const char *const *     v_subchannels;
+    const NMUtilsNamedValue s390_options[] = {
+        {.name = "layer2", .value_str = "0"},
+        {.name = "portno", .value_str = "1"},
+    };
+    int           i_s390_options_keys;
+    gs_free char *hostname            = NULL;
+    gint64        carrier_timeout_sec = 0;
+
+    connections = _parse(ARGV, &hostname, &carrier_timeout_sec);
+    g_assert_cmpint(g_hash_table_size(connections), ==, 2);
+    g_assert_cmpstr(hostname, ==, "foo.example.com");
+    g_assert_cmpint(carrier_timeout_sec, ==, 0);
+
+    connection = g_hash_table_lookup(connections, "enc800");
+    g_assert(NM_IS_CONNECTION(connection));
+
+    s_con = nm_connection_get_setting_connection(connection);
+    g_assert(NM_IS_SETTING_CONNECTION(s_con));
+    g_assert_cmpstr(nm_setting_connection_get_connection_type(s_con),
+                    ==,
+                    NM_SETTING_WIRED_SETTING_NAME);
+    g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "enc800");
+    g_assert_cmpstr(nm_setting_connection_get_interface_name(s_con), ==, "enc800");
+
+    s_wired = nm_connection_get_setting_wired(connection);
+    g_assert(NM_IS_SETTING_WIRED(s_wired));
+
+    v_subchannels = nm_setting_wired_get_s390_subchannels(s_wired);
+    g_assert(v_subchannels);
+    g_assert_cmpstr(v_subchannels[0], ==, "0.0.0800");
+    g_assert_cmpstr(v_subchannels[1], ==, "0.0.0801");
+    g_assert_cmpstr(v_subchannels[2], ==, "0.0.0802");
+    g_assert_cmpstr(v_subchannels[3], ==, NULL);
+
+    g_assert_cmpint(nm_setting_wired_get_num_s390_options(s_wired), ==, G_N_ELEMENTS(s390_options));
+    for (i_s390_options_keys = 0; i_s390_options_keys < G_N_ELEMENTS(s390_options);
+         i_s390_options_keys++) {
+        const NMUtilsNamedValue *s390_option = &s390_options[i_s390_options_keys];
+        const char *             k;
+        const char *             v;
+        const char *             v2;
+
+        g_assert(s390_option->name);
+        g_assert(s390_option->value_str);
+        v = nm_setting_wired_get_s390_option_by_key(s_wired, s390_option->name);
+        g_assert(v);
+        g_assert_cmpstr(v, ==, s390_option->value_str);
+
+        if (!nm_setting_wired_get_s390_option(s_wired, i_s390_options_keys, &k, &v2))
+            g_assert_not_reached();
+        g_assert_cmpstr(k, ==, s390_option->name);
+        g_assert(v == v2);
+        g_assert_cmpstr(v2, ==, s390_option->value_str);
+    }
+
+    nmtst_assert_connection_verifies_without_normalization(connection);
+
+    connection = g_hash_table_lookup(connections, "slc600");
+    g_assert(NM_IS_CONNECTION(connection));
+
+    s_con = nm_connection_get_setting_connection(connection);
+    g_assert(NM_IS_SETTING_CONNECTION(s_con));
+    g_assert_cmpstr(nm_setting_connection_get_connection_type(s_con),
+                    ==,
+                    NM_SETTING_WIRED_SETTING_NAME);
+    g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "slc600");
+    g_assert_cmpstr(nm_setting_connection_get_interface_name(s_con), ==, "slc600");
+
+    s_wired = nm_connection_get_setting_wired(connection);
+    g_assert(NM_IS_SETTING_WIRED(s_wired));
+
+    v_subchannels = nm_setting_wired_get_s390_subchannels(s_wired);
+    g_assert(v_subchannels);
+    g_assert_cmpstr(v_subchannels[0], ==, "0.0.0600");
+    g_assert_cmpstr(v_subchannels[1], ==, "0.0.0601");
+    g_assert_cmpstr(v_subchannels[2], ==, NULL);
+
+    nmtst_assert_connection_verifies_without_normalization(connection);
+}
+
+static void
+test_rd_znet_legacy(void)
+{
+    gs_unref_hashtable GHashTable *connections = NULL;
+    const char *const *const       ARGV =
+        NM_MAKE_STRV("ip=10.11.12.13::10.11.12.1:24:foo.example.com:eth0:none",
+                     "rd.znet=qeth,0.0.0800,0.0.0801,0.0.0802,layer2=0,portno=1",
+                     "rd.znet=ctc,0.0.0600,0.0.0601,layer2=0,portno=0",
+                     "ip=ctc0:dhcp",
+                     "net.ifnames=0");
+    NMConnection *       connection;
+    NMSettingConnection *s_con;
+    gs_free char *       hostname            = NULL;
+    gint64               carrier_timeout_sec = 0;
+
+    connections = _parse(ARGV, &hostname, &carrier_timeout_sec);
+    g_assert_cmpint(g_hash_table_size(connections), ==, 2);
+    g_assert_cmpstr(hostname, ==, "foo.example.com");
+    g_assert_cmpint(carrier_timeout_sec, ==, 0);
+
+    connection = g_hash_table_lookup(connections, "eth0");
+    g_assert(NM_IS_CONNECTION(connection));
+
+    s_con = nm_connection_get_setting_connection(connection);
+    g_assert(NM_IS_SETTING_CONNECTION(s_con));
+    g_assert_cmpstr(nm_setting_connection_get_connection_type(s_con),
+                    ==,
+                    NM_SETTING_WIRED_SETTING_NAME);
+    g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "eth0");
+    g_assert_cmpstr(nm_setting_connection_get_interface_name(s_con), ==, "eth0");
+
+    nmtst_assert_connection_verifies_without_normalization(connection);
+
+    connection = g_hash_table_lookup(connections, "ctc0");
+    g_assert(NM_IS_CONNECTION(connection));
+
+    s_con = nm_connection_get_setting_connection(connection);
+    g_assert(NM_IS_SETTING_CONNECTION(s_con));
+    g_assert_cmpstr(nm_setting_connection_get_connection_type(s_con),
+                    ==,
+                    NM_SETTING_WIRED_SETTING_NAME);
+    g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "ctc0");
+    g_assert_cmpstr(nm_setting_connection_get_interface_name(s_con), ==, "ctc0");
+
+    nmtst_assert_connection_verifies_without_normalization(connection);
+}
+
+static void
+test_rd_znet_no_ip(void)
+{
+    gs_unref_hashtable GHashTable *connections = NULL;
+    const char *const *const       ARGV =
+        NM_MAKE_STRV("rd.znet=qeth,0.0.0800,0.0.0801,0.0.0802,layer2=0,portno=1");
+
+    connections = _parse_cons(ARGV);
+    g_assert_cmpint(g_hash_table_size(connections), ==, 0);
+}
+
+static void
+test_rd_znet_malformed(void)
+{
+    const char *const *const ARGV0  = NM_MAKE_STRV("rd.znet=");
+    const char *const *const ARGV1  = NM_MAKE_STRV("rd.znet=,");
+    const char *const *const ARGV2  = NM_MAKE_STRV("rd.znet=foobar");
+    const char *const *const ARGV3  = NM_MAKE_STRV("rd.znet=qeth,0.0.0800,,,layer2=0,portno=1");
+    const char *const *const ARGV[] = {ARGV0, ARGV1, ARGV2, ARGV3};
+    guint                    i;
+
+    for (i = 0; i < G_N_ELEMENTS(ARGV); i++) {
+        gs_unref_hashtable GHashTable *connections = NULL;
+
+        connections = _parse_cons(ARGV[i]);
+        g_assert_cmpint(g_hash_table_size(connections), ==, 0);
+    }
+}
+
+static void
+test_bootif_ip(void)
+{
+    const char *const *ARGV                  = NM_MAKE_STRV("BOOTIF=00:53:AB:cd:02:03", "ip=dhcp");
+    gs_unref_object NMConnection *connection = NULL;
+    NMSettingWired *              s_wired;
+    NMSettingIPConfig *           s_ip4;
+    NMSettingIPConfig *           s_ip6;
+
+    connection = _parse_con(ARGV, "default_connection");
+
+    g_assert_cmpstr(nm_connection_get_id(connection), ==, "Wired Connection");
+
+    s_wired = nm_connection_get_setting_wired(connection);
+    g_assert_cmpstr(nm_setting_wired_get_mac_address(s_wired), ==, "00:53:AB:CD:02:03");
+    g_assert(s_wired);
+
+    s_ip4 = nm_connection_get_setting_ip4_config(connection);
+    g_assert(s_ip4);
+    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_AUTO);
+    g_assert(!nm_setting_ip_config_get_ignore_auto_dns(s_ip4));
+    g_assert(!nm_setting_ip_config_get_may_fail(s_ip4));
+
+    s_ip6 = nm_connection_get_setting_ip6_config(connection);
+    g_assert(s_ip6);
+    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_AUTO);
+    g_assert(!nm_setting_ip_config_get_ignore_auto_dns(s_ip6));
+}
+
+static void
+test_neednet_no_args(void)
+{
+    const char *const *ARGV                  = NM_MAKE_STRV("rd.neednet");
+    gs_unref_object NMConnection *connection = NULL;
+    NMSettingWired *              s_wired;
+    NMSettingIPConfig *           s_ip4;
+    NMSettingIPConfig *           s_ip6;
+
+    connection = _parse_con(ARGV, "default_connection");
+
+    g_assert_cmpstr(nm_connection_get_id(connection), ==, "Wired Connection");
+
+    s_wired = nm_connection_get_setting_wired(connection);
+    g_assert(s_wired);
+
+    s_ip4 = nm_connection_get_setting_ip4_config(connection);
+    g_assert(s_ip4);
+    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_AUTO);
+    g_assert(nm_setting_ip_config_get_may_fail(s_ip4));
+    g_assert_cmpint(nm_setting_ip_config_get_required_timeout(s_ip4),
+                    ==,
+                    NMI_IP_REQUIRED_TIMEOUT_MSEC);
+
+    s_ip6 = nm_connection_get_setting_ip6_config(connection);
+    g_assert(s_ip6);
+    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_AUTO);
+    g_assert(nm_setting_ip_config_get_may_fail(s_ip6));
+    g_assert_cmpint(nm_setting_ip_config_get_required_timeout(s_ip6), ==, -1);
+}
+
+static void
+test_neednet_args(void)
+{
+    gs_unref_hashtable GHashTable *connections = NULL;
+    const char *const *            ARGV        = NM_MAKE_STRV("rd.neednet",
+                                           "ip=eno1:dhcp",
+                                           "ip=172.25.1.100::172.25.1.1:24::eno2",
+                                           "bridge=br0:eno3");
+    NMConnection *                 connection;
+    NMSettingConnection *          s_con;
+
+    connections = _parse_cons(ARGV);
+    g_assert_cmpint(g_hash_table_size(connections), ==, 4);
+
+    connection = g_hash_table_lookup(connections, "eno1");
+    nmtst_assert_connection_verifies_without_normalization(connection);
+    s_con = nm_connection_get_setting_connection(connection);
+    g_assert(s_con);
+    g_assert_cmpstr(nm_setting_connection_get_interface_name(s_con), ==, "eno1");
+    g_assert_cmpint(nm_setting_connection_get_wait_device_timeout(s_con),
+                    ==,
+                    NMI_WAIT_DEVICE_TIMEOUT_MSEC);
+
+    connection = g_hash_table_lookup(connections, "eno2");
+    nmtst_assert_connection_verifies_without_normalization(connection);
+    s_con = nm_connection_get_setting_connection(connection);
+    g_assert(s_con);
+    g_assert_cmpstr(nm_setting_connection_get_interface_name(s_con), ==, "eno2");
+    g_assert_cmpint(nm_setting_connection_get_wait_device_timeout(s_con),
+                    ==,
+                    NMI_WAIT_DEVICE_TIMEOUT_MSEC);
+
+    connection = g_hash_table_lookup(connections, "eno3");
+    nmtst_assert_connection_verifies_without_normalization(connection);
+    s_con = nm_connection_get_setting_connection(connection);
+    g_assert(s_con);
+    g_assert_cmpstr(nm_setting_connection_get_interface_name(s_con), ==, "eno3");
+    g_assert_cmpint(nm_setting_connection_get_wait_device_timeout(s_con),
+                    ==,
+                    NMI_WAIT_DEVICE_TIMEOUT_MSEC);
+
+    connection = g_hash_table_lookup(connections, "br0");
+    nmtst_assert_connection_verifies_without_normalization(connection);
+    s_con = nm_connection_get_setting_connection(connection);
+    g_assert(s_con);
+    g_assert_cmpstr(nm_setting_connection_get_interface_name(s_con), ==, "br0");
+    g_assert_cmpint(nm_setting_connection_get_wait_device_timeout(s_con), ==, -1);
+}
+
+static void
+test_bootif_no_ip(void)
+{
+    const char *const *ARGV                  = NM_MAKE_STRV("BOOTIF=00:53:AB:cd:02:03");
+    gs_unref_object NMConnection *connection = NULL;
+    NMSettingWired *              s_wired;
+    NMSettingIPConfig *           s_ip4;
+    NMSettingIPConfig *           s_ip6;
+
+    connection = _parse_con(ARGV, "default_connection");
+
+    g_assert_cmpstr(nm_connection_get_id(connection), ==, "Wired Connection");
+
+    s_wired = nm_connection_get_setting_wired(connection);
+    g_assert_cmpstr(nm_setting_wired_get_mac_address(s_wired), ==, "00:53:AB:CD:02:03");
+    g_assert(s_wired);
+
+    s_ip4 = nm_connection_get_setting_ip4_config(connection);
+    g_assert(s_ip4);
+    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_AUTO);
+    g_assert(nm_setting_ip_config_get_may_fail(s_ip4));
+
+    s_ip6 = nm_connection_get_setting_ip6_config(connection);
+    g_assert(s_ip6);
+    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_AUTO);
+    g_assert(nm_setting_ip_config_get_may_fail(s_ip6));
+}
+
+static void
+test_bootif_hwtype(void)
+{
+    const char *const *ARGV0  = NM_MAKE_STRV("ip=eth0:dhcp", "BOOTIF=01-00-53-AB-cd-02-03");
+    const char *const *ARGV1  = NM_MAKE_STRV("ip=eth0:dhcp", "BOOTIF=00-00-53-Ab-cD-02-03");
+    const char *const *ARGV[] = {ARGV0, ARGV1};
+    guint              i;
+
+    for (i = 0; i < G_N_ELEMENTS(ARGV); i++) {
+        gs_unref_hashtable GHashTable *connections = NULL;
+        NMConnection *                 connection;
+        NMSettingWired *               s_wired;
+        NMSettingIPConfig *            s_ip4;
+        NMSettingIPConfig *            s_ip6;
+
+        connections = _parse_cons(ARGV[i]);
+        g_assert_cmpint(g_hash_table_size(connections), ==, 2);
+
+        connection = g_hash_table_lookup(connections, "eth0");
+        nmtst_assert_connection_verifies_without_normalization(connection);
+        g_assert_cmpstr(nm_connection_get_id(connection), ==, "eth0");
+
+        s_wired = nm_connection_get_setting_wired(connection);
+        g_assert(!nm_setting_wired_get_mac_address(s_wired));
+        g_assert(s_wired);
+
+        s_ip4 = nm_connection_get_setting_ip4_config(connection);
+        g_assert(s_ip4);
+        g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4),
+                        ==,
+                        NM_SETTING_IP4_CONFIG_METHOD_AUTO);
+        g_assert(!nm_setting_ip_config_get_ignore_auto_dns(s_ip4));
+        g_assert(!nm_setting_ip_config_get_may_fail(s_ip4));
+
+        s_ip6 = nm_connection_get_setting_ip6_config(connection);
+        g_assert(s_ip6);
+        g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6),
+                        ==,
+                        NM_SETTING_IP6_CONFIG_METHOD_AUTO);
+        g_assert(!nm_setting_ip_config_get_ignore_auto_dns(s_ip6));
+
+        connection = g_hash_table_lookup(connections, "bootif_connection");
+        nmtst_assert_connection_verifies_without_normalization(connection);
+        g_assert_cmpstr(nm_connection_get_id(connection), ==, "BOOTIF Connection");
+
+        s_wired = nm_connection_get_setting_wired(connection);
+        g_assert_cmpstr(nm_setting_wired_get_mac_address(s_wired), ==, "00:53:AB:CD:02:03");
+        g_assert(s_wired);
+
+        s_ip4 = nm_connection_get_setting_ip4_config(connection);
+        g_assert(s_ip4);
+        g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4),
+                        ==,
+                        NM_SETTING_IP4_CONFIG_METHOD_AUTO);
+        g_assert(!nm_setting_ip_config_get_ignore_auto_dns(s_ip4));
+        g_assert(nm_setting_ip_config_get_may_fail(s_ip4));
+
+        s_ip6 = nm_connection_get_setting_ip6_config(connection);
+        g_assert(s_ip6);
+        g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6),
+                        ==,
+                        NM_SETTING_IP6_CONFIG_METHOD_AUTO);
+        g_assert(!nm_setting_ip_config_get_ignore_auto_dns(s_ip6));
+        g_assert(nm_setting_ip_config_get_may_fail(s_ip6));
+    }
+}
+
+/* Check that nameservers are assigned to all existing
+ * connections that support the specific IPv4/IPv6 address
+ * family.
+ */
+static void
+test_nameserver(void)
+{
+    gs_unref_hashtable GHashTable *connections = NULL;
+    const char *const *            ARGV =
+        NM_MAKE_STRV("nameserver=1.1.1.1",
+                     "ip=eth0:dhcp",
+                     "ip=eth1:auto6",
+                     "ip=10.11.12.13::10.11.12.1:24:foo.example.com:eth2:none",
+                     "nameserver=1.0.0.1",
+                     "nameserver=[2606:4700:4700::1111]");
+    NMConnection *     connection;
+    NMSettingIPConfig *s_ip;
+    gs_free char *     hostname            = NULL;
+    gint64             carrier_timeout_sec = 0;
+
+    connections = _parse(ARGV, &hostname, &carrier_timeout_sec);
+    g_assert_cmpint(g_hash_table_size(connections), ==, 3);
+    g_assert_cmpstr(hostname, ==, "foo.example.com");
+    g_assert_cmpint(carrier_timeout_sec, ==, 0);
+
+    connection = g_hash_table_lookup(connections, "eth0");
+    nmtst_assert_connection_verifies_without_normalization(connection);
+
+    s_ip = nm_connection_get_setting_ip4_config(connection);
+    g_assert(s_ip);
+    g_assert_cmpint(nm_setting_ip_config_get_num_dns(s_ip), ==, 2);
+    g_assert_cmpstr(nm_setting_ip_config_get_dns(s_ip, 0), ==, "1.1.1.1");
+    g_assert_cmpstr(nm_setting_ip_config_get_dns(s_ip, 1), ==, "1.0.0.1");
+
+    connection = g_hash_table_lookup(connections, "eth1");
+    nmtst_assert_connection_verifies_without_normalization(connection);
+
+    s_ip = nm_connection_get_setting_ip6_config(connection);
+    g_assert(s_ip);
+    g_assert_cmpint(nm_setting_ip_config_get_num_dns(s_ip), ==, 1);
+    g_assert_cmpstr(nm_setting_ip_config_get_dns(s_ip, 0), ==, "2606:4700:4700::1111");
+
+    connection = g_hash_table_lookup(connections, "eth2");
+    nmtst_assert_connection_verifies_without_normalization(connection);
+
+    s_ip = nm_connection_get_setting_ip4_config(connection);
+    g_assert(s_ip);
+    g_assert_cmpint(nm_setting_ip_config_get_num_dns(s_ip), ==, 2);
+    g_assert_cmpstr(nm_setting_ip_config_get_dns(s_ip, 0), ==, "1.1.1.1");
+    g_assert_cmpstr(nm_setting_ip_config_get_dns(s_ip, 1), ==, "1.0.0.1");
+}
+
+static void
+test_bootif_off(void)
+{
+    gs_unref_hashtable GHashTable *connections = NULL;
+    const char *const *ARGV = NM_MAKE_STRV("BOOTIF=01-00-53-AB-cd-02-03", "rd.bootif=0");
+
+    connections = _parse_cons(ARGV);
+    g_assert_cmpint(g_hash_table_size(connections), ==, 0);
+}
+
+static void
+test_dhcp_vendor_class_id(void)
+{
+    const char *const *ARGV;
+    gs_unref_object NMConnection *connection = NULL;
+    NMSettingIP4Config *          s_ip4;
+    gs_free char *                vci_long          = NULL;
+    char                          vci_arg_long[512] = {0};
+
+    ARGV       = NM_MAKE_STRV("rd.net.dhcp.vendor-class=testvci", "ip=eno1:dhcp");
+    connection = _parse_con(ARGV, "eno1");
+    s_ip4      = NM_SETTING_IP4_CONFIG(nm_connection_get_setting_ip4_config(connection));
+    g_assert_cmpstr(nm_setting_ip4_config_get_dhcp_vendor_class_identifier(s_ip4), ==, "testvci");
+
+    g_clear_object(&connection);
+
+    ARGV       = NM_MAKE_STRV("rd.net.dhcp.vendor-class", "ip=eno1:dhcp");
+    connection = _parse_con(ARGV, "eno1");
+    s_ip4      = NM_SETTING_IP4_CONFIG(nm_connection_get_setting_ip4_config(connection));
+    g_assert(nm_setting_ip4_config_get_dhcp_vendor_class_identifier(s_ip4) == NULL);
+
+    g_clear_object(&connection);
+
+    memset(vci_arg_long, 'A', 400);
+    vci_long   = g_strdup_printf("rd.net.dhcp.vendor-class=%s", vci_arg_long);
+    ARGV       = NM_MAKE_STRV(vci_long, "ip=eno1:dhcp");
+    connection = _parse_con(ARGV, "eno1");
+    s_ip4      = NM_SETTING_IP4_CONFIG(nm_connection_get_setting_ip4_config(connection));
+    g_assert(nm_setting_ip4_config_get_dhcp_vendor_class_identifier(s_ip4) == NULL);
+}
+
+static void
+test_infiniband_iface(void)
+{
+    const char *const *ARGV                  = NM_MAKE_STRV("ip=ib1:dhcp");
+    gs_unref_object NMConnection *connection = NULL;
+    NMSettingInfiniband *         s_ib;
+
+    connection = _parse_con(ARGV, "ib1");
+
+    g_assert_cmpstr(nm_connection_get_connection_type(connection),
+                    ==,
+                    NM_SETTING_INFINIBAND_SETTING_NAME);
+    s_ib = nm_connection_get_setting_infiniband(connection);
+    g_assert(s_ib);
+}
+
+static void
+test_infiniband_mac(void)
+{
+    const char *const *ARGV =
+        NM_MAKE_STRV("ip=00-11-22-33-44-55-66-77-88-99-aa-bb-cc-dd-ee-ff-00-11-22-33:dhcp");
+    gs_unref_object NMConnection *connection = NULL;
+    NMSettingInfiniband *         s_ib;
+
+    connection = _parse_con(ARGV, "00:11:22:33:44:55:66:77:88:99:AA:BB:CC:DD:EE:FF:00:11:22:33");
+
+    g_assert_cmpstr(nm_connection_get_connection_type(connection),
+                    ==,
+                    NM_SETTING_INFINIBAND_SETTING_NAME);
+    g_assert_cmpstr(nm_connection_get_interface_name(connection), ==, NULL);
+    s_ib = nm_connection_get_setting_infiniband(connection);
+    g_assert(s_ib);
+    g_assert_cmpstr(nm_setting_infiniband_get_mac_address(s_ib),
+                    ==,
+                    "00:11:22:33:44:55:66:77:88:99:AA:BB:CC:DD:EE:FF:00:11:22:33");
+}
+
+static void
+test_infiniband_pkey(void)
+{
+    const char *const *const ARGV = NM_MAKE_STRV("ib.pkey=ib0.8004", "ip=ib0.8004:dhcp");
+    gs_unref_hashtable GHashTable *connections = NULL;
+    NMConnection *                 connection;
+    NMSettingInfiniband *          s_ib;
+    NMSettingIPConfig *            s_ip4;
+    NMSettingIPConfig *            s_ip6;
+
+    connections = _parse_cons(ARGV);
+    g_assert_cmpint(g_hash_table_size(connections), ==, 1);
+
+    connection = g_hash_table_lookup(connections, "ib0.8004");
+    g_assert_cmpstr(nm_connection_get_connection_type(connection),
+                    ==,
+                    NM_SETTING_INFINIBAND_SETTING_NAME);
+    g_assert_cmpstr(nm_connection_get_interface_name(connection), ==, "ib0.8004");
+
+    s_ib = nm_connection_get_setting_infiniband(connection);
+    g_assert(s_ib);
+    g_assert_cmpint(nm_setting_infiniband_get_p_key(s_ib), ==, 0x8004);
+
+    s_ip4 = nm_connection_get_setting_ip4_config(connection);
+    g_assert(s_ip4);
+    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_AUTO);
+    g_assert(!nm_setting_ip_config_get_may_fail(s_ip4));
+
+    s_ip6 = nm_connection_get_setting_ip6_config(connection);
+    g_assert(s_ip6);
+    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_AUTO);
+    g_assert(nm_setting_ip_config_get_may_fail(s_ip6));
+}
+
+static void
+test_carrier_timeout(void)
+{
+    gs_unref_hashtable GHashTable *connections         = NULL;
+    const char *const *            ARGV                = NM_MAKE_STRV("rd.net.timeout.carrier=20");
+    gs_free char *                 hostname            = NULL;
+    gint64                         carrier_timeout_sec = 0;
+
+    connections = _parse(ARGV, &hostname, &carrier_timeout_sec);
+    g_assert_cmpint(g_hash_table_size(connections), ==, 0);
+    g_assert_cmpstr(hostname, ==, NULL);
+    g_assert_cmpint(carrier_timeout_sec, ==, 20);
+}
+
+/* Obs1.: this function is implemented as macro, and not as a function,
+ * to show the correct line in g_assert() debug */
+#define _ethtool_connection_check_and_get(connection)                                \
+    ({                                                                               \
+        NMSettingWired *_s_wired    = NULL;                                          \
+        NMConnection *  _connection = connection;                                    \
+                                                                                     \
+        g_assert(nm_connection_get_setting_connection(_connection));                 \
+        g_assert(nm_connection_is_type(_connection, NM_SETTING_WIRED_SETTING_NAME)); \
+        g_assert(nm_connection_get_setting_ip4_config(_connection));                 \
+        g_assert(nm_connection_get_setting_ip6_config(_connection));                 \
+        _s_wired = nm_connection_get_setting_wired(_connection);                     \
+        g_assert(NM_IS_SETTING_WIRED(_s_wired));                                     \
+                                                                                     \
+        _s_wired;                                                                    \
+    })
+
+static void
+test_rd_ethtool(void)
+{
+    const char *const *ARGV        = NULL;
+    NMConnection *     connection  = NULL;
+    GHashTable *       connections = NULL;
+    NMSettingWired *   s_wired     = NULL;
+
+    ARGV = NM_MAKE_STRV("rd.ethtool=");
+    NMTST_EXPECT_NM_WARN("cmdline-reader: Impossible to set rd.ethtool options: invalid format");
+    connections = _parse_cons(ARGV);
+    g_assert_cmpint(g_hash_table_size(connections), ==, 0);
+    g_hash_table_unref(connections);
+    g_test_assert_expected_messages();
+
+    ARGV = NM_MAKE_STRV("rd.ethtool=eth0");
+    NMTST_EXPECT_NM_WARN("cmdline-reader: Could not find rd.ethtool options to set");
+    connections = _parse_cons(ARGV);
+    g_assert_cmpint(g_hash_table_size(connections), ==, 0);
+    g_hash_table_unref(connections);
+    g_test_assert_expected_messages();
+
+    ARGV = NM_MAKE_STRV("rd.ethtool=eth0:");
+    NMTST_EXPECT_NM_WARN("cmdline-reader: Could not find rd.ethtool options to set");
+    connections = _parse_cons(ARGV);
+    g_assert_cmpint(g_hash_table_size(connections), ==, 0);
+    g_hash_table_unref(connections);
+    g_test_assert_expected_messages();
+
+    ARGV = NM_MAKE_STRV("rd.ethtool=::");
+    NMTST_EXPECT_NM_WARN("cmdline-reader: Impossible to set rd.ethtool options: invalid format");
+    connections = _parse_cons(ARGV);
+    g_assert_cmpint(g_hash_table_size(connections), ==, 0);
+    g_test_assert_expected_messages();
+    g_hash_table_unref(connections);
+
+    ARGV       = NM_MAKE_STRV("rd.ethtool=eth0:on");
+    connection = _parse_con(ARGV, "eth0");
+    s_wired    = _ethtool_connection_check_and_get(connection);
+    g_assert(nm_setting_wired_get_auto_negotiate(s_wired));
+    g_object_unref(connection);
+
+    ARGV       = NM_MAKE_STRV("rd.ethtool=eth0:off");
+    connection = _parse_con(ARGV, "eth0");
+    s_wired    = _ethtool_connection_check_and_get(connection);
+    g_assert(!nm_setting_wired_get_auto_negotiate(s_wired));
+    g_object_unref(connection);
+
+    ARGV       = NM_MAKE_STRV("rd.ethtool=eth0:true");
+    connection = _parse_con(ARGV, "eth0");
+    s_wired    = _ethtool_connection_check_and_get(connection);
+    g_assert(nm_setting_wired_get_auto_negotiate(s_wired));
+    g_object_unref(connection);
+
+    ARGV       = NM_MAKE_STRV("rd.ethtool=eth0:false");
+    connection = _parse_con(ARGV, "eth0");
+    s_wired    = _ethtool_connection_check_and_get(connection);
+    g_assert(!nm_setting_wired_get_auto_negotiate(s_wired));
+    g_object_unref(connection);
+
+    ARGV       = NM_MAKE_STRV("rd.ethtool=eth0:1");
+    connection = _parse_con(ARGV, "eth0");
+    s_wired    = _ethtool_connection_check_and_get(connection);
+    g_assert(nm_setting_wired_get_auto_negotiate(s_wired));
+    g_object_unref(connection);
+
+    ARGV       = NM_MAKE_STRV("rd.ethtool=eth0:0");
+    connection = _parse_con(ARGV, "eth0");
+    s_wired    = _ethtool_connection_check_and_get(connection);
+    g_assert(!nm_setting_wired_get_auto_negotiate(s_wired));
+    g_object_unref(connection);
+
+    ARGV = NM_MAKE_STRV("rd.ethtool=eth0:randomstring");
+    NMTST_EXPECT_NM_WARN(
+        "cmdline-reader: Invalid value for rd.ethtool.autoneg, rd.ethtool.autoneg was not set");
+    connections = _parse_cons(ARGV);
+    g_assert_cmpint(g_hash_table_size(connections), ==, 1);
+    g_test_assert_expected_messages();
+    g_hash_table_unref(connections);
+
+    ARGV        = NM_MAKE_STRV("rd.ethtool=eth0::");
+    connections = _parse_cons(ARGV);
+    g_assert_cmpint(g_hash_table_size(connections), ==, 1);
+    g_hash_table_unref(connections);
+
+    ARGV = NM_MAKE_STRV("rd.ethtool=eth0::astring");
+    NMTST_EXPECT_NM_WARN(
+        "cmdline-reader: Invalid value for rd.ethtool.speed, rd.ethtool.speed was not set");
+    connections = _parse_cons(ARGV);
+    g_assert_cmpint(g_hash_table_size(connections), ==, 1);
+    g_test_assert_expected_messages();
+    g_hash_table_unref(connections);
+
+    ARGV = NM_MAKE_STRV("rd.ethtool=eth0::1000000000000000000000000000000000000");
+    NMTST_EXPECT_NM_WARN(
+        "cmdline-reader: Invalid value for rd.ethtool.speed, rd.ethtool.speed was not set");
+    connections = _parse_cons(ARGV);
+    g_assert_cmpint(g_hash_table_size(connections), ==, 1);
+    g_test_assert_expected_messages();
+    g_hash_table_unref(connections);
+
+    ARGV = NM_MAKE_STRV("rd.ethtool=eth0::0.67");
+    NMTST_EXPECT_NM_WARN(
+        "cmdline-reader: Invalid value for rd.ethtool.speed, rd.ethtool.speed was not set");
+    connections = _parse_cons(ARGV);
+    g_assert_cmpint(g_hash_table_size(connections), ==, 1);
+    g_test_assert_expected_messages();
+    g_hash_table_unref(connections);
+
+    ARGV = NM_MAKE_STRV("rd.ethtool=eth0::-23");
+    NMTST_EXPECT_NM_WARN(
+        "cmdline-reader: Invalid value for rd.ethtool.speed, rd.ethtool.speed was not set");
+    connections = _parse_cons(ARGV);
+    g_assert_cmpint(g_hash_table_size(connections), ==, 1);
+    g_test_assert_expected_messages();
+    g_hash_table_unref(connections);
+
+    ARGV       = NM_MAKE_STRV("rd.ethtool=eth0:1:10");
+    connection = _parse_con(ARGV, "eth0");
+    s_wired    = _ethtool_connection_check_and_get(connection);
+    g_assert(nm_setting_wired_get_auto_negotiate(s_wired));
+    g_assert_cmpint(nm_setting_wired_get_speed(s_wired), ==, 10);
+    g_assert_cmpstr(nm_setting_wired_get_duplex(s_wired), ==, "full");
+    g_object_unref(connection);
+
+    ARGV       = NM_MAKE_STRV("rd.ethtool=eth0::100");
+    connection = _parse_con(ARGV, "eth0");
+    s_wired    = _ethtool_connection_check_and_get(connection);
+    g_assert(!nm_setting_wired_get_auto_negotiate(s_wired));
+    g_assert_cmpint(nm_setting_wired_get_speed(s_wired), ==, 100);
+    g_assert_cmpstr(nm_setting_wired_get_duplex(s_wired), ==, "full");
+    g_object_unref(connection);
+
+    ARGV = NM_MAKE_STRV("rd.ethtool=eth0:::bogus");
+    NMTST_EXPECT_NM_WARN(
+        "cmdline-reader: Invalid extra argument 'bogus' for rd.ethtool, this value was not set");
+    connections = _parse_cons(ARGV);
+    g_assert_cmpint(g_hash_table_size(connections), ==, 1);
+    g_test_assert_expected_messages();
+    g_hash_table_unref(connections);
+
+    ARGV = NM_MAKE_STRV("rd.ethtool=eth0::10:bogus");
+    NMTST_EXPECT_NM_WARN(
+        "cmdline-reader: Invalid extra argument 'bogus' for rd.ethtool, this value was not set");
+    connection = _parse_con(ARGV, "eth0");
+    s_wired    = _ethtool_connection_check_and_get(connection);
+    g_assert(!nm_setting_wired_get_auto_negotiate(s_wired));
+    g_assert_cmpint(nm_setting_wired_get_speed(s_wired), ==, 10);
+    g_assert_cmpstr(nm_setting_wired_get_duplex(s_wired), ==, "full");
+    g_test_assert_expected_messages();
+    g_object_unref(connection);
+
+    ARGV = NM_MAKE_STRV("rd.ethtool=eth0:on:100:bogus");
+    NMTST_EXPECT_NM_WARN(
+        "cmdline-reader: Invalid extra argument 'bogus' for rd.ethtool, this value was not set");
+    connection = _parse_con(ARGV, "eth0");
+    s_wired    = _ethtool_connection_check_and_get(connection);
+    g_assert(nm_setting_wired_get_auto_negotiate(s_wired));
+    g_assert_cmpint(nm_setting_wired_get_speed(s_wired), ==, 100);
+    g_assert_cmpstr(nm_setting_wired_get_duplex(s_wired), ==, "full");
+    g_test_assert_expected_messages();
+    g_object_unref(connection);
+
+    ARGV = NM_MAKE_STRV("rd.ethtool=eth0:on:100:bogus");
+    NMTST_EXPECT_NM_WARN(
+        "cmdline-reader: Invalid extra argument 'bogus' for rd.ethtool, this value was not set");
+    connection = _parse_con(ARGV, "eth0");
+    s_wired    = _ethtool_connection_check_and_get(connection);
+    g_assert(nm_setting_wired_get_auto_negotiate(s_wired));
+    g_assert_cmpint(nm_setting_wired_get_speed(s_wired), ==, 100);
+    g_assert_cmpstr(nm_setting_wired_get_duplex(s_wired), ==, "full");
+    g_test_assert_expected_messages();
+    g_object_unref(connection);
+
+    ARGV = NM_MAKE_STRV("rd.ethtool=:::");
+    NMTST_EXPECT_NM_WARN("cmdline-reader: Impossible to set rd.ethtool options: invalid format");
+    connections = _parse_cons(ARGV);
+    g_assert_cmpint(g_hash_table_size(connections), ==, 0);
+    g_test_assert_expected_messages();
+    g_hash_table_unref(connections);
+}
+
+/*****************************************************************************/
+
+static void
+test_plain_equal_char(void)
+{
+    _parse_no_con(NM_MAKE_STRV("="));
+    _parse_no_con(NM_MAKE_STRV("=foo"));
+    _parse_no_con(NM_MAKE_STRV("BOOT_IMAGE=(hd0,msdos2)/boot/vmlinuz-5.13.10-100.fc33.x86_64",
+                               "root=UUID=ff252b4a-8294-4961-abcb-74c8fc868db7",
+                               "ro",
+                               "rhgb",
+                               "quiet",
+                               "pci",
+                               "=",
+                               "nomsi,",
+                               "noaer"));
+}
+
+/*****************************************************************************/
+
+NMTST_DEFINE();
+
+int
+main(int argc, char **argv)
+{
+    nmtst_init_assert_logging(&argc, &argv, "INFO", "DEFAULT");
+
+    g_test_add_func("/initrd/cmdline/auto", test_auto);
+    g_test_add_func("/initrd/cmdline/dhcp_with_hostname", test_dhcp_with_hostname);
+    g_test_add_func("/initrd/cmdline/dhcp_with_mtu", test_dhcp_with_mtu);
+    g_test_add_func("/initrd/cmdline/dhcp_timeout", test_dhcp_timeout);
+    g_test_add_func("/initrd/cmdline/if_auto_with_mtu", test_if_auto_with_mtu);
+    g_test_add_func("/initrd/cmdline/if_dhcp6", test_if_dhcp6);
+    g_test_add_func("/initrd/cmdline/if_auto_with_mtu_and_mac", test_if_auto_with_mtu_and_mac);
+    g_test_add_func("/initrd/cmdline/if_ip4_manual", test_if_ip4_manual);
+    g_test_add_func("/initrd/cmdline/if_ip4_manual_no_dev", test_if_ip4_manual_no_dev);
+    g_test_add_func("/initrd/cmdline/if_ip6_manual", test_if_ip6_manual);
+    g_test_add_func("/initrd/cmdline/if_mac_ifname", test_if_mac_ifname);
+    g_test_add_func("/initrd/cmdline/if_off", test_if_off);
+    g_test_add_func("/initrd/cmdline/multiple/merge", test_multiple_merge);
+    g_test_add_func("/initrd/cmdline/multiple/bootdev", test_multiple_bootdev);
+    g_test_add_func("/initrd/cmdline/nameserver", test_nameserver);
+    g_test_add_func("/initrd/cmdline/some_more", test_some_more);
+    g_test_add_func("/initrd/cmdline/bootdev", test_bootdev);
+    g_test_add_func("/initrd/cmdline/bond", test_bond);
+    g_test_add_func("/initrd/cmdline/bond/ip", test_bond_ip);
+    g_test_add_func("/initrd/cmdline/bond/default", test_bond_default);
+    g_test_add_func("/initrd/cmdline/team", test_team);
+    g_test_add_func("/initrd/cmdline/vlan", test_vlan);
+    g_test_add_func("/initrd/cmdline/vlan/dhcp-on-parent", test_vlan_with_dhcp_on_parent);
+    g_test_add_func("/initrd/cmdline/vlan/over-bond", test_vlan_over_bond);
+    g_test_add_func("/initrd/cmdline/bridge", test_bridge);
+    g_test_add_func("/initrd/cmdline/bridge/default", test_bridge_default);
+    g_test_add_func("/initrd/cmdline/bridge/ip", test_bridge_ip);
+    g_test_add_func("/initrd/cmdline/ibft/ip_dev", test_ibft_ip_dev);
+    g_test_add_func("/initrd/cmdline/ibft/ip_dev_mac", test_ibft_ip_dev_mac);
+    g_test_add_func("/initrd/cmdline/ibft/ip", test_ibft_ip);
+    g_test_add_func("/initrd/cmdline/ibft/rd_iscsi_ibft", test_ibft_rd_iscsi_ibft);
+    g_test_add_func("/initrd/cmdline/ignore_extra", test_ignore_extra);
+    g_test_add_func("/initrd/cmdline/rd_znet", test_rd_znet);
+    g_test_add_func("/initrd/cmdline/rd_znet/legacy", test_rd_znet_legacy);
+    g_test_add_func("/initrd/cmdline/rd_znet/no_ip", test_rd_znet_no_ip);
+    g_test_add_func("/initrd/cmdline/rd_znet/empty", test_rd_znet_malformed);
+    g_test_add_func("/initrd/cmdline/bootif/ip", test_bootif_ip);
+    g_test_add_func("/initrd/cmdline/bootif/no_ip", test_bootif_no_ip);
+    g_test_add_func("/initrd/cmdline/bootif/hwtype", test_bootif_hwtype);
+    g_test_add_func("/initrd/cmdline/bootif/off", test_bootif_off);
+    g_test_add_func("/initrd/cmdline/neednet/no_args", test_neednet_no_args);
+    g_test_add_func("/initrd/cmdline/neednet/args", test_neednet_args);
+    g_test_add_func("/initrd/cmdline/dhcp/vendor_class_id", test_dhcp_vendor_class_id);
+    g_test_add_func("/initrd/cmdline/infiniband/iface", test_infiniband_iface);
+    g_test_add_func("/initrd/cmdline/infiniband/mac", test_infiniband_mac);
+    g_test_add_func("/initrd/cmdline/infiniband/pkey", test_infiniband_pkey);
+    g_test_add_func("/initrd/cmdline/carrier_timeout", test_carrier_timeout);
+    g_test_add_func("/initrd/cmdline/rd_ethtool", test_rd_ethtool);
+    g_test_add_func("/initrd/cmdline/plain_equal_char", test_plain_equal_char);
+
+    return g_test_run();
+}
diff --git a/src/nm-initrd-generator/tests/test-dt-reader.c b/src/nm-initrd-generator/tests/test-dt-reader.c
new file mode 100644
index 00000000..c1c28e06
--- /dev/null
+++ b/src/nm-initrd-generator/tests/test-dt-reader.c
@@ -0,0 +1,143 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2014 - 2018 Red Hat, Inc.
+ */
+
+#include "src/core/nm-default-daemon.h"
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/socket.h>
+
+#include "libnm-core-intern/nm-core-internal.h"
+
+#include "nm-initrd-generator/nm-initrd-generator.h"
+
+#include "libnm-glib-aux/nm-test-utils.h"
+
+#define TEST_INITRD_DIR NM_BUILD_SRCDIR "/src/nm-initrd-generator/tests"
+
+/*****************************************************************************/
+
+static void
+test_read_dt_ofw(void)
+{
+    NMConnection *       connection;
+    NMSettingConnection *s_con;
+    NMSettingWired *     s_wired;
+    NMSettingIPConfig *  s_ip4;
+    NMSettingIPConfig *  s_ip6;
+    const char *         mac_address;
+
+    connection = nmi_dt_reader_parse(TEST_INITRD_DIR "/sysfs-dt");
+    g_assert(connection);
+    nmtst_assert_connection_verifies(connection);
+
+    s_con = nm_connection_get_setting_connection(connection);
+    g_assert(s_con);
+    g_assert_cmpstr(nm_setting_connection_get_connection_type(s_con),
+                    ==,
+                    NM_SETTING_WIRED_SETTING_NAME);
+    g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "OpenFirmware Connection");
+    g_assert_cmpint(nm_setting_connection_get_timestamp(s_con), ==, 0);
+    g_assert(nm_setting_connection_get_autoconnect(s_con));
+
+    s_wired = nm_connection_get_setting_wired(connection);
+    g_assert(s_wired);
+    mac_address = nm_setting_wired_get_mac_address(s_wired);
+    g_assert(mac_address);
+    g_assert(nm_utils_hwaddr_matches(mac_address, -1, "ac:7f:3e:e5:d8:d8", -1));
+    g_assert(!nm_setting_wired_get_duplex(s_wired));
+    g_assert_cmpint(nm_setting_wired_get_speed(s_wired), ==, 0);
+    g_assert_cmpint(nm_setting_wired_get_mtu(s_wired), ==, 0);
+
+    s_ip4 = nm_connection_get_setting_ip4_config(connection);
+    g_assert(s_ip4);
+    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_AUTO);
+    g_assert_cmpstr(nm_setting_ip_config_get_dhcp_hostname(s_ip4), ==, "demiurge");
+
+    s_ip6 = nm_connection_get_setting_ip6_config(connection);
+    g_assert(s_ip6);
+    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_AUTO);
+
+    g_object_unref(connection);
+}
+
+static void
+test_read_dt_slof(void)
+{
+    NMConnection *       connection;
+    NMSettingConnection *s_con;
+    NMSettingWired *     s_wired;
+    NMSettingIPConfig *  s_ip4;
+    NMSettingIPConfig *  s_ip6;
+    NMIPAddress *        ip4_addr;
+
+    connection = nmi_dt_reader_parse(TEST_INITRD_DIR "/sysfs-dt-tftp");
+    g_assert(connection);
+    nmtst_assert_connection_verifies(connection);
+
+    s_con = nm_connection_get_setting_connection(connection);
+    g_assert(s_con);
+    g_assert_cmpstr(nm_setting_connection_get_connection_type(s_con),
+                    ==,
+                    NM_SETTING_WIRED_SETTING_NAME);
+    g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "OpenFirmware Connection");
+    g_assert_cmpint(nm_setting_connection_get_timestamp(s_con), ==, 0);
+    g_assert(nm_setting_connection_get_autoconnect(s_con));
+
+    s_wired = nm_connection_get_setting_wired(connection);
+    g_assert(s_wired);
+    g_assert(!nm_setting_wired_get_mac_address(s_wired));
+    g_assert_cmpstr(nm_setting_wired_get_duplex(s_wired), ==, "half");
+    g_assert_cmpint(nm_setting_wired_get_speed(s_wired), ==, 10);
+    g_assert_cmpint(nm_setting_wired_get_mtu(s_wired), ==, 0);
+
+    s_ip4 = nm_connection_get_setting_ip4_config(connection);
+    g_assert(s_ip4);
+    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4),
+                    ==,
+                    NM_SETTING_IP4_CONFIG_METHOD_MANUAL);
+
+    g_assert_cmpint(nm_setting_ip_config_get_num_addresses(s_ip4), ==, 1);
+    ip4_addr = nm_setting_ip_config_get_address(s_ip4, 0);
+    g_assert(ip4_addr);
+    g_assert_cmpstr(nm_ip_address_get_address(ip4_addr), ==, "192.168.32.2");
+    g_assert_cmpint(nm_ip_address_get_prefix(ip4_addr), ==, 16);
+
+    g_assert_cmpstr(nm_setting_ip_config_get_gateway(s_ip4), ==, "192.168.32.1");
+
+    s_ip6 = nm_connection_get_setting_ip6_config(connection);
+    g_assert(s_ip6);
+    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6),
+                    ==,
+                    NM_SETTING_IP6_CONFIG_METHOD_DISABLED);
+
+    g_object_unref(connection);
+}
+
+static void
+test_read_dt_none(void)
+{
+    NMConnection *connection;
+
+    connection = nmi_dt_reader_parse(TEST_INITRD_DIR "/sysfs");
+    g_assert(!connection);
+}
+
+NMTST_DEFINE();
+
+int
+main(int argc, char **argv)
+{
+    nmtst_init_assert_logging(&argc, &argv, "INFO", "DEFAULT");
+
+    g_test_add_func("/initrd/dt/ofw", test_read_dt_ofw);
+    g_test_add_func("/initrd/dt/slof", test_read_dt_slof);
+    g_test_add_func("/initrd/dt/none", test_read_dt_none);
+
+    return g_test_run();
+}
diff --git a/src/nm-initrd-generator/tests/test-ibft-reader.c b/src/nm-initrd-generator/tests/test-ibft-reader.c
new file mode 100644
index 00000000..0d437519
--- /dev/null
+++ b/src/nm-initrd-generator/tests/test-ibft-reader.c
@@ -0,0 +1,302 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2014 - 2018 Red Hat, Inc.
+ */
+
+#include "src/core/nm-default-daemon.h"
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/socket.h>
+
+#include "libnm-core-intern/nm-core-internal.h"
+
+#include "nm-initrd-generator/nm-initrd-generator.h"
+
+#include "libnm-glib-aux/nm-test-utils.h"
+
+#define TEST_INITRD_DIR NM_BUILD_SRCDIR "/src/nm-initrd-generator/tests"
+
+/*****************************************************************************/
+
+static NMConnection *
+read_connection(const char *sysfs_dir, const char *expected_mac, GError **error)
+{
+    NMConnection *     connection       = NULL;
+    gs_unref_hashtable GHashTable *ibft = NULL;
+    gs_free char *                 mac  = NULL;
+    GHashTable *                   nic  = NULL;
+
+    ibft = nmi_ibft_read(sysfs_dir);
+
+    mac = g_ascii_strup(expected_mac, -1);
+    nic = g_hash_table_lookup(ibft, mac);
+    if (!nic)
+        return NULL;
+
+    connection = nm_simple_connection_new();
+
+    if (!nmi_ibft_update_connection_from_nic(connection, nic, error))
+        g_clear_object(&connection);
+
+    return connection;
+}
+
+static void
+test_read_ibft_dhcp(void)
+{
+    NMConnection *       connection;
+    NMSettingConnection *s_con;
+    NMSettingWired *     s_wired;
+    NMSettingIPConfig *  s_ip4;
+    NMSettingIPConfig *  s_ip6;
+    GError *             error = NULL;
+    const char *         mac_address;
+    const char *         expected_mac_address = "00:33:21:98:b9:f1";
+
+    connection = read_connection(TEST_INITRD_DIR "/sysfs-dhcp", expected_mac_address, &error);
+    g_assert_no_error(error);
+    nmtst_assert_connection_verifies_without_normalization(connection);
+
+    g_assert(!nm_connection_get_setting_vlan(connection));
+
+    s_con = nm_connection_get_setting_connection(connection);
+    g_assert(s_con);
+    g_assert_cmpstr(nm_setting_connection_get_connection_type(s_con),
+                    ==,
+                    NM_SETTING_WIRED_SETTING_NAME);
+    g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "iBFT Connection 1");
+    g_assert_cmpstr(nm_setting_connection_get_interface_name(s_con), ==, NULL);
+    g_assert_cmpint(nm_setting_connection_get_timestamp(s_con), ==, 0);
+    g_assert(nm_setting_connection_get_autoconnect(s_con));
+
+    s_wired = nm_connection_get_setting_wired(connection);
+    g_assert(s_wired);
+    mac_address = nm_setting_wired_get_mac_address(s_wired);
+    g_assert(mac_address);
+    g_assert(nm_utils_hwaddr_matches(mac_address, -1, expected_mac_address, -1));
+    g_assert_cmpint(nm_setting_wired_get_mtu(s_wired), ==, 0);
+
+    s_ip4 = nm_connection_get_setting_ip4_config(connection);
+    g_assert(s_ip4);
+    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_AUTO);
+
+    s_ip6 = nm_connection_get_setting_ip6_config(connection);
+    g_assert(s_ip6);
+    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6),
+                    ==,
+                    NM_SETTING_IP6_CONFIG_METHOD_DISABLED);
+
+    g_object_unref(connection);
+}
+
+static void
+test_read_ibft_static(void)
+{
+    NMConnection *       connection;
+    NMSettingConnection *s_con;
+    NMSettingWired *     s_wired;
+    NMSettingIPConfig *  s_ip4;
+    NMSettingIPConfig *  s_ip6;
+    GError *             error = NULL;
+    const char *         mac_address;
+    const char *         expected_mac_address = "00:33:21:98:b9:f0";
+    NMIPAddress *        ip4_addr;
+
+    connection = read_connection(TEST_INITRD_DIR "/sysfs-static", expected_mac_address, &error);
+    g_assert_no_error(error);
+    nmtst_assert_connection_verifies_without_normalization(connection);
+
+    g_assert(!nm_connection_get_setting_vlan(connection));
+
+    s_con = nm_connection_get_setting_connection(connection);
+    g_assert(s_con);
+    g_assert_cmpstr(nm_setting_connection_get_connection_type(s_con),
+                    ==,
+                    NM_SETTING_WIRED_SETTING_NAME);
+    g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "iBFT Connection 0");
+    g_assert_cmpstr(nm_setting_connection_get_interface_name(s_con), ==, NULL);
+    g_assert_cmpint(nm_setting_connection_get_timestamp(s_con), ==, 0);
+    g_assert(nm_setting_connection_get_autoconnect(s_con));
+
+    s_wired = nm_connection_get_setting_wired(connection);
+    g_assert(s_wired);
+    mac_address = nm_setting_wired_get_mac_address(s_wired);
+    g_assert(mac_address);
+    g_assert(nm_utils_hwaddr_matches(mac_address, -1, expected_mac_address, -1));
+    g_assert_cmpint(nm_setting_wired_get_mtu(s_wired), ==, 0);
+
+    s_ip4 = nm_connection_get_setting_ip4_config(connection);
+    g_assert(s_ip4);
+    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4),
+                    ==,
+                    NM_SETTING_IP4_CONFIG_METHOD_MANUAL);
+
+    g_assert_cmpint(nm_setting_ip_config_get_num_dns(s_ip4), ==, 2);
+    g_assert_cmpstr(nm_setting_ip_config_get_dns(s_ip4, 0), ==, "10.16.255.2");
+    g_assert_cmpstr(nm_setting_ip_config_get_dns(s_ip4, 1), ==, "10.16.255.3");
+
+    g_assert_cmpint(nm_setting_ip_config_get_num_addresses(s_ip4), ==, 1);
+    ip4_addr = nm_setting_ip_config_get_address(s_ip4, 0);
+    g_assert(ip4_addr);
+    g_assert_cmpstr(nm_ip_address_get_address(ip4_addr), ==, "192.168.32.72");
+    g_assert_cmpint(nm_ip_address_get_prefix(ip4_addr), ==, 22);
+
+    g_assert_cmpstr(nm_setting_ip_config_get_gateway(s_ip4), ==, "192.168.35.254");
+
+    s_ip6 = nm_connection_get_setting_ip6_config(connection);
+    g_assert(s_ip6);
+    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6),
+                    ==,
+                    NM_SETTING_IP6_CONFIG_METHOD_DISABLED);
+
+    g_object_unref(connection);
+}
+
+static void
+test_read_ibft_bad_address(gconstpointer user_data)
+{
+    const char *  sysfs_dir = user_data;
+    NMConnection *connection;
+    GError *      error = NULL;
+
+    g_assert(g_file_test(sysfs_dir, G_FILE_TEST_EXISTS));
+
+    connection = read_connection(sysfs_dir, "00:33:21:98:b9:f0", &error);
+    g_assert(connection == NULL);
+    g_assert(error);
+    g_clear_error(&error);
+}
+
+static void
+test_read_ibft_vlan(void)
+{
+    NMConnection *       connection;
+    NMSettingConnection *s_con;
+    NMSettingWired *     s_wired;
+    NMSettingVlan *      s_vlan;
+    NMSettingIPConfig *  s_ip4;
+    const char *         mac_address;
+    const char *         expected_mac_address = "00:33:21:98:b9:f0";
+    NMIPAddress *        ip4_addr;
+    GError *             error = NULL;
+
+    connection = read_connection(TEST_INITRD_DIR "/sysfs-vlan", expected_mac_address, &error);
+    g_assert_no_error(error);
+    nmtst_assert_connection_verifies_without_normalization(connection);
+
+    s_con = nm_connection_get_setting_connection(connection);
+    g_assert(s_con);
+    g_assert_cmpstr(nm_setting_connection_get_connection_type(s_con),
+                    ==,
+                    NM_SETTING_VLAN_SETTING_NAME);
+    g_assert_cmpstr(nm_setting_connection_get_interface_name(s_con), ==, NULL);
+
+    /* ===== WIRED SETTING ===== */
+    s_wired = nm_connection_get_setting_wired(connection);
+    g_assert(s_wired);
+    mac_address = nm_setting_wired_get_mac_address(s_wired);
+    g_assert(mac_address);
+    g_assert(nm_utils_hwaddr_matches(mac_address, -1, expected_mac_address, -1));
+
+    /* ===== VLAN SETTING ===== */
+    s_vlan = nm_connection_get_setting_vlan(connection);
+    g_assert(s_vlan);
+    g_assert_cmpint(nm_setting_vlan_get_id(s_vlan), ==, 123);
+    g_assert_cmpstr(nm_setting_vlan_get_parent(s_vlan), ==, NULL);
+
+    /* ===== IPv4 SETTING ===== */
+    s_ip4 = nm_connection_get_setting_ip4_config(connection);
+    g_assert(s_ip4);
+    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4),
+                    ==,
+                    NM_SETTING_IP4_CONFIG_METHOD_MANUAL);
+
+    g_assert_cmpint(nm_setting_ip_config_get_num_dns(s_ip4), ==, 0);
+
+    g_assert_cmpint(nm_setting_ip_config_get_num_addresses(s_ip4), ==, 1);
+    ip4_addr = nm_setting_ip_config_get_address(s_ip4, 0);
+    g_assert(ip4_addr);
+    g_assert_cmpstr(nm_ip_address_get_address(ip4_addr), ==, "192.168.6.200");
+    g_assert_cmpint(nm_ip_address_get_prefix(ip4_addr), ==, 24);
+
+    g_assert_cmpstr(nm_setting_ip_config_get_gateway(s_ip4), ==, NULL);
+
+    g_object_unref(connection);
+}
+
+static void
+test_read_ibft(void)
+{
+    NMConnection *     connection;
+    NMSettingIPConfig *s_ip4;
+    NMSettingIPConfig *s_ip6;
+    GError *           error = NULL;
+
+    /* This test doesn't actually test too much (apart from the presence of
+     * IPv6 that is not covered by other tests), but the test fixture is a good
+     * example of about everything that can be included in iBFT table (as of
+     * ACPI 3.0b). */
+
+    connection = read_connection(TEST_INITRD_DIR "/sysfs", "00:53:00:AB:00:01", &error);
+    g_assert(connection);
+    g_assert_no_error(error);
+
+    s_ip4 = nm_connection_get_setting_ip4_config(connection);
+    nmtst_assert_connection_verifies_without_normalization(connection);
+    g_assert(nm_setting_ip_config_get_num_addresses(s_ip4) == 0);
+    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4),
+                    ==,
+                    NM_SETTING_IP4_CONFIG_METHOD_DISABLED);
+
+    s_ip6 = nm_connection_get_setting_ip6_config(connection);
+    g_assert(nm_setting_ip_config_get_num_addresses(s_ip6) == 1);
+    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_AUTO);
+    g_object_unref(connection);
+
+    connection = read_connection(TEST_INITRD_DIR "/sysfs", "00:53:06:66:AB:01", &error);
+    g_assert(connection);
+    g_assert_no_error(error);
+    nmtst_assert_connection_verifies_without_normalization(connection);
+
+    s_ip4 = nm_connection_get_setting_ip4_config(connection);
+    g_assert(nm_setting_ip_config_get_num_addresses(s_ip4) == 1);
+    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_AUTO);
+
+    s_ip6 = nm_connection_get_setting_ip6_config(connection);
+    g_assert(nm_setting_ip_config_get_num_addresses(s_ip6) == 0);
+    g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6),
+                    ==,
+                    NM_SETTING_IP6_CONFIG_METHOD_DISABLED);
+    g_object_unref(connection);
+}
+
+NMTST_DEFINE();
+
+int
+main(int argc, char **argv)
+{
+    nmtst_init_assert_logging(&argc, &argv, "INFO", "DEFAULT");
+
+    g_test_add_func("/initrd/ibft", test_read_ibft);
+    g_test_add_func("/initrd/ibft/dhcp", test_read_ibft_dhcp);
+    g_test_add_func("/initrd/ibft/static", test_read_ibft_static);
+    g_test_add_func("/initrd/ibft/vlan", test_read_ibft_vlan);
+    g_test_add_data_func("/initrd/ibft/bad-ipaddr-read",
+                         TEST_INITRD_DIR "/sysfs-bad-ipaddr",
+                         test_read_ibft_bad_address);
+    g_test_add_data_func("/initrd/ibft/bad-gateway-read",
+                         TEST_INITRD_DIR "/sysfs-bad-gateway",
+                         test_read_ibft_bad_address);
+    g_test_add_data_func("/initrd/ibft/bad-dns1-read",
+                         TEST_INITRD_DIR "/sysfs-bad-dns1",
+                         test_read_ibft_bad_address);
+    g_test_add_data_func("/initrd/ibft/bad-dns2-read",
+                         TEST_INITRD_DIR "/sysfs-bad-dns2",
+                         test_read_ibft_bad_address);
+
+    return g_test_run();
+}