From 6304d514406c782fec7956203ca8315778511edf Mon Sep 17 00:00:00 2001 From: Tomas Bzatek Date: Fri, 15 Aug 2025 16:40:01 +0200 Subject: [PATCH 1/3] nm-initrd-generator: rework NBFT HFI DHCP detection There are several flags specified in the NVMe Boot Specification that may indicate DHCP was used to acquire information during the pre-OS phase. This commit considers these additional sources, based on actual NBFT table contents from different systems. Although we've seen slight variations in firmware implementations regarding the HFI IP Origin values when DHCP was configured, the new set of rules still align with expectations. --- src/nm-initrd-generator/nmi-nbft-reader.c | 31 +++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/src/nm-initrd-generator/nmi-nbft-reader.c b/src/nm-initrd-generator/nmi-nbft-reader.c index 5d12086f96..0e0bd53277 100644 --- a/src/nm-initrd-generator/nmi-nbft-reader.c +++ b/src/nm-initrd-generator/nmi-nbft-reader.c @@ -94,6 +94,33 @@ find_conn_for_wired_mac(GPtrArray *a, const char *hwaddr) return NULL; } +static gboolean +hfi_is_dhcp(struct nbft_info_hfi *hfi, int family) +{ + /* There are several flags that may indicate the HFI is set for DHCP + * per NVM Express® Boot Specification, Revision 1.3. As the HFI + * Transport Flags (HFITFLAGS) are not publicly exposed by the libnvme + * API, only the DHCP Override (DHCPO) flag and the IP Origin (IPORIG) + * value is available. + * + * The bit 03 of the HFI Transport Flags (HFITFLAGS) is about an advanced + * stateless mechanism - IPv6-SLAAC and IPv6-ND, stating that "the DHCP + * Override bit shall be cleared to 0, and the IP Origin field shall + * be cleared to 0". This nm-initrd-generator will ignore this flag, + * expecting an IP address to be provided by the usual HFI fields + * just like in a static adressing case. + * + * DHCP Override (DHCPO): "The HFI information was populated by + * consuming the DHCP on this interface." + * + * IP Origin (IPORIG): "If set to 3h (IpPrefixOriginDhcp), then the + * IP Address was acquired through DHCP, and the IP Address specified + * in this HFI should not be reused by the OS." + */ + return hfi->tcp_info.dhcp_override || hfi->tcp_info.ip_origin == 3 /* IpPrefixOriginDhcp */ + || is_valid_addr(family, hfi->tcp_info.dhcp_server_ipaddr); +} + static NMConnection * create_wired_conn(struct nbft_info_hfi *hfi, const char *conn_name, @@ -208,7 +235,7 @@ parse_hfi(GPtrArray *a, struct nbft_info_hfi *hfi, const char *table_name, char NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_DISABLED, NULL); - if (is_valid_addr(AF_INET, hfi->tcp_info.dhcp_server_ipaddr)) { + if (hfi_is_dhcp(hfi, family)) { g_object_set(s_ip4, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO, @@ -260,7 +287,7 @@ parse_hfi(GPtrArray *a, struct nbft_info_hfi *hfi, const char *table_name, char NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_DISABLED, NULL); - if (is_valid_addr(AF_INET6, hfi->tcp_info.dhcp_server_ipaddr)) { + if (hfi_is_dhcp(hfi, family)) { g_object_set(s_ip6, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_AUTO, From 592a4f077bfa4d3c4d46ca16af3c6a7fbd26e974 Mon Sep 17 00:00:00 2001 From: Tomas Bzatek Date: Fri, 15 Aug 2025 17:34:50 +0200 Subject: [PATCH 2/3] nm-initrd-generator: fix a conn_name leak --- src/nm-initrd-generator/nmi-nbft-reader.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/nm-initrd-generator/nmi-nbft-reader.c b/src/nm-initrd-generator/nmi-nbft-reader.c index 0e0bd53277..dfab0390af 100644 --- a/src/nm-initrd-generator/nmi-nbft-reader.c +++ b/src/nm-initrd-generator/nmi-nbft-reader.c @@ -210,6 +210,7 @@ parse_hfi(GPtrArray *a, struct nbft_info_hfi *hfi, const char *table_name, char return; } g_ptr_array_add(a, parent_connection); + nm_clear_g_free(&conn_name); } conn_name = format_conn_name(table_name, hfi, TRUE); From dce149352de801a9f8cfb35333c1961efd0cb3a8 Mon Sep 17 00:00:00 2001 From: Tomas Bzatek Date: Tue, 12 Aug 2025 17:22:04 +0200 Subject: [PATCH 3/3] nm-initrd-generator: add NBFT parser tests This adds simple unit tests for most common NBFT deployments. Sample data were mostly taken from the upstream libnvme repository. --- src/nm-initrd-generator/tests/meson.build | 4 + .../acpi/tables/NBFT-Dell.PowerEdge.R760 | Bin 0 -> 1017 bytes .../firmware/acpi/tables/NBFT-dhcp-ipv4 | Bin 0 -> 825 bytes ...ell.PowerEdge.R660-fw1.5.5-mpath+discovery | Bin 0 -> 4147 bytes .../firmware/acpi/tables/NBFT-multi | Bin 0 -> 2589 bytes .../firmware/acpi/tables/NBFT-rhpoc | Bin 0 -> 724 bytes .../firmware/acpi/tables/NBFT-static-ipv4 | Bin 0 -> 725 bytes .../firmware/acpi/tables/NBFT-auto-ipv6 | Bin 0 -> 721 bytes .../firmware/acpi/tables/NBFT-dhcp-ipv6 | Bin 0 -> 725 bytes .../firmware/acpi/tables/NBFT-ipv6-noip+disc | Bin 0 -> 785 bytes .../firmware/acpi/tables/NBFT-static-ipv6 | Bin 0 -> 721 bytes .../acpi/tables/NBFT-qemu-vlans-incomplete | Bin 0 -> 2200 bytes .../tests/test-nbft-reader.c | 397 ++++++++++++++++++ 13 files changed, 401 insertions(+) create mode 100644 src/nm-initrd-generator/tests/nbft-ipv4-dhcp/firmware/acpi/tables/NBFT-Dell.PowerEdge.R760 create mode 100644 src/nm-initrd-generator/tests/nbft-ipv4-dhcp/firmware/acpi/tables/NBFT-dhcp-ipv4 create mode 100644 src/nm-initrd-generator/tests/nbft-ipv4-static/firmware/acpi/tables/NBFT-Dell.PowerEdge.R660-fw1.5.5-mpath+discovery create mode 100644 src/nm-initrd-generator/tests/nbft-ipv4-static/firmware/acpi/tables/NBFT-multi create mode 100644 src/nm-initrd-generator/tests/nbft-ipv4-static/firmware/acpi/tables/NBFT-rhpoc create mode 100644 src/nm-initrd-generator/tests/nbft-ipv4-static/firmware/acpi/tables/NBFT-static-ipv4 create mode 100644 src/nm-initrd-generator/tests/nbft-ipv6-auto/firmware/acpi/tables/NBFT-auto-ipv6 create mode 100644 src/nm-initrd-generator/tests/nbft-ipv6-auto/firmware/acpi/tables/NBFT-dhcp-ipv6 create mode 100644 src/nm-initrd-generator/tests/nbft-ipv6-auto/firmware/acpi/tables/NBFT-ipv6-noip+disc create mode 100644 src/nm-initrd-generator/tests/nbft-ipv6-static/firmware/acpi/tables/NBFT-static-ipv6 create mode 100644 src/nm-initrd-generator/tests/nbft-vlan/firmware/acpi/tables/NBFT-qemu-vlans-incomplete create mode 100644 src/nm-initrd-generator/tests/test-nbft-reader.c diff --git a/src/nm-initrd-generator/tests/meson.build b/src/nm-initrd-generator/tests/meson.build index 8fa3bcac8d..897a214867 100644 --- a/src/nm-initrd-generator/tests/meson.build +++ b/src/nm-initrd-generator/tests/meson.build @@ -6,6 +6,10 @@ test_units = [ 'test-cmdline-reader', ] +if enable_nbft + test_units += [ 'test-nbft-reader' ] +endif + foreach test_unit : test_units exe = executable( test_unit, diff --git a/src/nm-initrd-generator/tests/nbft-ipv4-dhcp/firmware/acpi/tables/NBFT-Dell.PowerEdge.R760 b/src/nm-initrd-generator/tests/nbft-ipv4-dhcp/firmware/acpi/tables/NBFT-Dell.PowerEdge.R760 new file mode 100644 index 0000000000000000000000000000000000000000..2dea9363435394e6a72ec5e669566edafd9e6635 GIT binary patch literal 1017 zcmbtSzi-n(6n>W`jk-WogaixnP@z>N^3ro&iv~rig_gxK;)NLtN7^zdg-ljClwIcb&!g3j| zuWK!!m%pGYH`V45ZMcoNzEJCbhS|)_zlzlgP)Gcie+zj6j}dKnhj>x{RiggsC#-Y> zz9DX$Ya$vHr7I&t8bS}5DRmJ9hVE`lUk_d1ceW)rrEP7NqCs@fj*Fo$99wWxXTo8+ zsJJMOxUC1=6^;>@h80+wqtU3_ueC9aUP9+dhjQ0(bk1o#Ii!ua-S+m9r*RrKnlY`~ zl2N=?VM!bE1n(2_PzLyLvv~C45~bz>HF6O$I_34C%i%(N#_K`bipljCn>)irW4oUbprg9?6QZgbQofjw+r5 zZB}@mrxyI;7MZCHV{5Wm+{gpUOQ60o2Q46V?6@w1;}KTq{1EI@%&f&oG7xK*S!4t8Rw#E`M# zA3%VFU}HyuG9YziU`Ap>0*Qs0iJ{!9NfSCSaFXxqcfR}Gy(?bSmNfwK-Mi{vy3z1% zF8d7>KvDK2LU#$kXZ)01QNWB4%q;UE9UfbzOtFh$cB!x|i^fKhP;Qwbwqu*iSVEoP zaiM+~8DDP$ULG$tWxu<-^NK$^Gn<(Df4sdKb?Ny+yUHf3>^4cQ<|oH$Q6(wvo@wY<|GQq^|Iicwr_7Mc!6a7o3n mKAoW|E)0`_(`<67Gv2b9kc?}N8ruBFby>GpBw3l}oA4Wp(~|)J literal 0 HcmV?d00001 diff --git a/src/nm-initrd-generator/tests/nbft-ipv4-static/firmware/acpi/tables/NBFT-Dell.PowerEdge.R660-fw1.5.5-mpath+discovery b/src/nm-initrd-generator/tests/nbft-ipv4-static/firmware/acpi/tables/NBFT-Dell.PowerEdge.R660-fw1.5.5-mpath+discovery new file mode 100644 index 0000000000000000000000000000000000000000..0fbb35cf77f7071cee76af966eb8640180b31135 GIT binary patch literal 4147 zcmcJRO>7%Q7>2)DyK$U9R_z6W1U_&`g?7C^hfr{cT)D5GP92#h|1BhuHczehahhOUcVuep)_zHU1oZKJ`9+wGN-rw@{PD zM~Du0vHnjpDg^ulqKTwJJ^q;?@UM?8-1s$m@duy(%7qIc8}J!fP?PG=(ELcie;v_8 zdK20&|F_{YdIxIKIy5vt8t^v}O{Bk|{qny7pV8k?lZ?>;@DBz2hY(Gq6Ht$j>8HpG z*RCaBeXn@D{p{Hvf1dtj40q??Gn$7M=^`|A{zC!(3q%uX9omoo9ehULLyI&yHUNH% zj(IzT(S3*}(hSt&_b%8h@EOfQi*ybeI{)E-e+khmH{rC^UXY??%NN+*I=0C)|6Z%6$x{KDJ_uR7ahnRpf z`FG!+z0exWsK*hWD!G%n>8-H^EBXp)^VvQpm8X042&>V}y*nk=*mi%afgKFckW ztGc9cOObfa#*YiCDLJamEzQxjl#@D2)#a+JDJqu~ORhCe%GK5>_oaHnZ8p=ZtBaL1 zFXNNq@D&K>sv=p6u1F=TtndZSQE-j_&wHMt+bEVdB(~6R|tP)qW%7Rug4K0%~GXjhmdvj5BSLW;Wbh9cOTzAW*R7!P? zlB&9ud4ro3MYr8~+p@X6kZ!J)nx~s9?)C&W3`4;T9rD4Mu5}fpw!H|ng8~ov;OV`< zn+KM0Y#;D}WjwqOxU-Ce5c@6eBlMe7*wye>>gE6tBl{paPmM5HjQWUY_Ihe;4glf3 zn-lGg=&ZgVi^1);aUcBJp3AJdZ#uQC1sKjM8K literal 0 HcmV?d00001 diff --git a/src/nm-initrd-generator/tests/nbft-ipv4-static/firmware/acpi/tables/NBFT-multi b/src/nm-initrd-generator/tests/nbft-ipv4-static/firmware/acpi/tables/NBFT-multi new file mode 100644 index 0000000000000000000000000000000000000000..c34875bcf59e88603c08f0872c34d1463c65c592 GIT binary patch literal 2589 zcmcIkT}V@57=FLAKkaHvDCv(ufsQ&mJ7;Ix*$Q;O1VWjXbeYZ}LT$RuVM!$6MbSke zcu|RY6BI_>bWw=mjTdFJ3-h8Yy(n+G2`UOA)^nyux8;mndtuLezW4d|JnwnG?K>HW zoH?+Ih}{aD3Z7`U2F|qxtq4M>xek=oK=ezGHS$@NC0F z%EyZOePW!p)-q=r?2s+lsqEBL)*^Qd-nL}m64GeWF{ayC;9(ln*EYPj98l9Ub(Z}fL)8=87%6zDv#Vt<|HpMsj1Mu4jSYt_HK{oO~y z-sZ2P52ApCcR8%;W=>KYxyzz%%j#1?mS@>~GZkN1$e=F<|-g=jbkY zM&m$%-T*81H);OMP&3nKVEOas=o@%O-+=-()cyzm8qMDaH8ZsU%b!0-t>7880R_4S ztn~ejOueDTpmdO)0T1JMR~Sad;ZAy==YMR$M>36`U_c3kf?htNgaf=Bamu{kANKRk za9H+7+%D1W7i~f$6Y0GWYYYcu#UqPO-XSXvUJiOC-Ww4;d`R@liWG86u8_+{@&347 za)>hTQ0$3hk3F8b7#r+M#!@NYz(8-ePn4Xp%k5G4&aP;80cdrvLzKwGa5<8$9rX=C-IP1TdGDV0{QgCpr^pHC1(uVfe9id~eDed^4G W?MB|+n~EkfvE(J%Qp5Rg8ovRqU!xEJ literal 0 HcmV?d00001 diff --git a/src/nm-initrd-generator/tests/nbft-ipv4-static/firmware/acpi/tables/NBFT-rhpoc b/src/nm-initrd-generator/tests/nbft-ipv4-static/firmware/acpi/tables/NBFT-rhpoc new file mode 100644 index 0000000000000000000000000000000000000000..5d0a6cc0086235f0cd2d5933f1c284e6c8273531 GIT binary patch literal 724 zcmbVJ&1(}u6o1nMLP1cgSWhL#^zhP|-Pzrlp4?9ap$fK;gO_A?s{xyS#6&4Va}_*_ z^wu7F(0io^p;Z3`dnkApTK@$hzUgY3iXix4-q-Ip^Z3142$IF)2>^Bw+z;`;a!=|kqlwQtJ aSz4o;Yll0+^1Q4Clcdpn_7$l99`qB*|8)TX literal 0 HcmV?d00001 diff --git a/src/nm-initrd-generator/tests/nbft-ipv4-static/firmware/acpi/tables/NBFT-static-ipv4 b/src/nm-initrd-generator/tests/nbft-ipv4-static/firmware/acpi/tables/NBFT-static-ipv4 new file mode 100644 index 0000000000000000000000000000000000000000..bf3f8404b4eb30d582f48a8c55e130bc939779ea GIT binary patch literal 725 zcmbVJy-(Xf6n}>!@zI6Sfp*J;U^v%zK4Uvm{aKb4XoCb&t11pAM1mOXB!vZKMC?$h z6WzLZXgX9vOdYzm3j+fqe?)kP+Yk^FPx8Hw-|yb@@7-%REdLn-AdBw2H}|&aE-!dR zG(eO72|_Ojz#)FpFG*m)h^zyF4%Uk3k8@8>(04$hxyift+0gLC%J(ntm5(pK{hlm$ zyU%_cA=B?u6+)DLg25T0oq(tfPu?*u}GexE!aPuYKPCnY{XYu<+s2<q4XwbXBGd(SoWP-a5C|unHQ21fW}b)bu)Yyb z2d=P8!E~w#OQXWGIkiJ(QlHtv;=axe-(Ot^8Bj>z#aM{OOJ6 zUhgLEb8eUJQu6#AuJO@rVxGyrPS$9)5oZJN_24lOf@}B^xl+z4<9C#*QIa&(t)yCt j(s(mY)pn(pRvJwz+cwp#6=l1b#$gmi%GaKP;{PdEU=Mf! literal 0 HcmV?d00001 diff --git a/src/nm-initrd-generator/tests/nbft-ipv6-auto/firmware/acpi/tables/NBFT-auto-ipv6 b/src/nm-initrd-generator/tests/nbft-ipv6-auto/firmware/acpi/tables/NBFT-auto-ipv6 new file mode 100644 index 0000000000000000000000000000000000000000..64457d7d894e46e36f86ba9ca3a2f3dc667076cc GIT binary patch literal 721 zcmbVJyKWOf6ulEivfL495Cz&YDeh)wJ?q_dm3@tZ6o>`pQPB7?2^N0gi5*DgB0vYC z0STmtU!XvA5I!L_KY-vHLb!uPWDqnt(%w6J&b>2p?p#Y${b&Jz?IxS)`VA+!Q%hBx z)_~v;E|9dw0AA2%^Gz$vfmt3HOo?+Sznx`vNO=lYox%403k$`|U*8SCZ#>!jP`Z6o zJa8_(q{{5Hw7^*5^oJH-NS)3Riwu_FSH*x_oP#OFMbhnYh5hGO4|~y-d!H`CtvAoU zy(0Fp^$JfZR^TJW^K*NhWvM31L7Id~mPV+;JVB|-65}|Jv7F~JRux}VVzIKSCaTlb z%XuQhK#DSQ8FG|q*R4ktf| zT04v9zk2TeZ;bZV!$Av8R~zA@8T#?44mJW`Uy!)bpZeX literal 0 HcmV?d00001 diff --git a/src/nm-initrd-generator/tests/nbft-ipv6-auto/firmware/acpi/tables/NBFT-dhcp-ipv6 b/src/nm-initrd-generator/tests/nbft-ipv6-auto/firmware/acpi/tables/NBFT-dhcp-ipv6 new file mode 100644 index 0000000000000000000000000000000000000000..20715eeb3755a3b1cfd11383b185ef6ff7419ca8 GIT binary patch literal 725 zcmbVJ&o3lF6n3>s>s5@m)iLNhd(6 zXl}c+jBV_0!(NW^*KwJqTTu#a5BGr(T*XN=m2yrQZ&Rv-aa>h);!-|LqU|VA>c#b> bSgBH3wyLDHFg-|B4qYfxPJ0+~Z=ZMuZDDQ! literal 0 HcmV?d00001 diff --git a/src/nm-initrd-generator/tests/nbft-ipv6-auto/firmware/acpi/tables/NBFT-ipv6-noip+disc b/src/nm-initrd-generator/tests/nbft-ipv6-auto/firmware/acpi/tables/NBFT-ipv6-noip+disc new file mode 100644 index 0000000000000000000000000000000000000000..7a0690cb9ab504388e3031b27eecef3c84498a5d GIT binary patch literal 785 zcmb7ByGjF55S?p+!9vjZ0j^*Xk(=zjd$X@XlFjZ`L42kW@sTVN(5Q)q2!g2vLBtQR zvaqvJBuxq%A%!1eVPR+Etg8?=cv$f7sGs;V zb+FPXJiS*9mvHL|)lgloazPzgQK_(PPK~T;QOB?>J*zTB)zT9wx9*lVy@X>4T@y^9 zve0EJat4ZBrcs+2Lg%)^({_3SD!Y{=mzkilp4_f(BrEkTud!40YBh6zzg#jIS43LX zbh?J1>j+vz&>(Nfj6;mza?uXr1ut*g#}5FZRfh)&qL*(c44B_MxqmGAn&+eOxp!@D ztkvrIiGUDX#_Rk%U9wcJ6}RhN^#BI2_b;vZTbSG{?wG06l2AA^Ere;ZWz#R5`di&M D#@%lL literal 0 HcmV?d00001 diff --git a/src/nm-initrd-generator/tests/nbft-ipv6-static/firmware/acpi/tables/NBFT-static-ipv6 b/src/nm-initrd-generator/tests/nbft-ipv6-static/firmware/acpi/tables/NBFT-static-ipv6 new file mode 100644 index 0000000000000000000000000000000000000000..07b09cfba5bd22277bd63d53a86b8e4499eabe2e GIT binary patch literal 721 zcmbVJJ#14k5I#4RqHF~=2K2^sxQFfd{bix=&oET9f+84L@?)xqG)dzo&`w!^fr$kP z2E@z;5@JIjgv8pJ9U-x?gE$kY0)nNVLAkB5I8RJfP+L6-O+9xi~PGQOqO%bne+3@-uMk9Ip0XSgM}+{CxCf{qDxA+SSAA z6Yumx$}EmjD~wf+4z&45>}(;h%-{t4%ovi26_}A-Cf+?)dG_MnhhqKw`$u0x`6(>x z6uslL!acGfye4~c;jZIs^|T)4S)3Jlf;uiURJx%sP0JJ;WvNmf1|m$w>RCP2y}qfJ znTjJN8pu`5QRRumM2iRuk*HV}4H*={Dhzf9zT`q7kNx3z+aFAK%ef>z8lY_g_+1){dk3 zubS)sYoq)1XxKs9H&z5_M*;l#K060WNlpWq3ziav^t;Bl6KnjPTfKhgX7j*ItUqmS bk6VL1bXV>X-M0IdE2xn`H|ZL9zd!W@iY0CV literal 0 HcmV?d00001 diff --git a/src/nm-initrd-generator/tests/nbft-vlan/firmware/acpi/tables/NBFT-qemu-vlans-incomplete b/src/nm-initrd-generator/tests/nbft-vlan/firmware/acpi/tables/NBFT-qemu-vlans-incomplete new file mode 100644 index 0000000000000000000000000000000000000000..da385318de24539b0a2ed72eef4d2dad91a4aeed GIT binary patch literal 2200 zcmcIlOK1~O6umE#q<*@HDX3VLKm}WLW-^n>m!i$&gCJP7vADENLn&xdlQcwau?rEG z(v23Sb|Yvj7I#XiltLF;f(vymE_CBgyK@oG%cq?L8=6iV&Vg~ZJPMd1$E>(52Y;UU z>e?{1Uu^XKFT8^`}wIMsq-} z|BmZFnrTnYp44wI{V>hGef%Z@IOEgZ?5Y1qMD7a0Qvi`asA(I--|E0dX}HxTRVK<i$Jdb_b|~ict$HgnSKJB*0)ymEjWcX+7H}XU!Zn= zR_O?^gMz?j^{tGb$rvgfr3~;`-HS(ao!*e{)59UZ81+STQH#1XF&K;lMOP%E1*0Cf z;t48Uax@nmxti#V=$g-~DK62e`JAE_@~fghs(8h);@5m?*rmF|?k-ARPfDs&(L|?D zN~MRTWbRrbKblTtGJ&zNk)eR1x-_@P>k|hC<3k3h=KW4Zr51)C2NDj#@x>UWS6}j- z*@$9s`Pt1GPFA9nFf2g2Sgexe@n83~t4jtR8Ccj`Z(ux7W1#N&|6)Ke8fdLI zFtM`+HeaZ+yPBpt;bH6kN`t9XRvJyk1KC6-D`p4M!-*{IMk8xmvsoEkLMIt*yR>QN zN|*lT3|0-(W?h>byB@D>h-n*pZE0M3qEcFDP&$xIB{K 0) { + if (!s_vlan) + continue; + if (nm_setting_vlan_get_id(s_vlan) != vlan_id) + continue; + } else if (s_vlan) + continue; + return *c; + } + + return NULL; +} + +static void +verify_connection(NMConnection *c, const char *expected_mac, guint32 expected_vlan_id) +{ + NMSettingConnection *s_con; + NMSettingWired *s_wired; + NMSettingVlan *s_vlan; + const char *mac_address; + + nmtst_assert_connection_verifies_without_normalization(c); + + s_con = nm_connection_get_setting_connection(c); + g_assert(s_con); + + g_assert(g_str_has_prefix(nm_setting_connection_get_id(s_con), "NBFT")); + g_assert_cmpstr(nm_setting_connection_get_interface_name(s_con), ==, NULL); + g_assert(nm_setting_connection_get_autoconnect_priority(s_con) + == NMI_AUTOCONNECT_PRIORITY_FIRMWARE); + + s_wired = nm_connection_get_setting_wired(c); + 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, -1)); + + if (expected_vlan_id > 0) { + g_assert_cmpstr(nm_setting_connection_get_connection_type(s_con), + ==, + NM_SETTING_VLAN_SETTING_NAME); + s_vlan = nm_connection_get_setting_vlan(c); + g_assert(s_vlan); + g_assert_cmpint(nm_setting_vlan_get_id(s_vlan), ==, expected_vlan_id); + g_assert_cmpstr(nm_setting_vlan_get_parent(s_vlan), ==, NULL); + } else { + g_assert_cmpstr(nm_setting_connection_get_connection_type(s_con), + ==, + NM_SETTING_WIRED_SETTING_NAME); + } +} + +static void +verify_ipv4(NMConnection *c, const char *addr, int mask, const char *gateway) +{ + NMSettingIPConfig *s_ip4; + NMIPAddress *ip4_addr; + + s_ip4 = nm_connection_get_setting_ip4_config(c); + 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), ==, addr); + g_assert_cmpint(nm_ip_address_get_prefix(ip4_addr), ==, mask); + + g_assert_cmpstr(nm_setting_ip_config_get_gateway(s_ip4), ==, gateway); +} + +static void +verify_ipv4_dhcp(NMConnection *c) +{ + NMSettingIPConfig *s_ip4; + + s_ip4 = nm_connection_get_setting_ip4_config(c); + g_assert(s_ip4); + g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_AUTO); +} + +static void +verify_ipv4_disabled(NMConnection *c) +{ + NMSettingIPConfig *s_ip4; + + s_ip4 = nm_connection_get_setting_ip4_config(c); + g_assert(s_ip4); + g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4), + ==, + NM_SETTING_IP4_CONFIG_METHOD_DISABLED); +} + +static void +verify_ipv6(NMConnection *c, const char *addr, int prefix, const char *gateway) +{ + NMSettingIPConfig *s_ip6; + NMIPAddress *ip6_addr; + + s_ip6 = nm_connection_get_setting_ip6_config(c); + g_assert(s_ip6); + g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6), + ==, + NM_SETTING_IP6_CONFIG_METHOD_MANUAL); + + 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), ==, 1); + ip6_addr = nm_setting_ip_config_get_address(s_ip6, 0); + g_assert(ip6_addr); + g_assert_cmpstr(nm_ip_address_get_address(ip6_addr), ==, addr); + g_assert_cmpint(nm_ip_address_get_prefix(ip6_addr), ==, prefix); + + g_assert_cmpstr(nm_setting_ip_config_get_gateway(s_ip6), ==, gateway); +} + +static void +verify_ipv6_auto(NMConnection *c) +{ + NMSettingIPConfig *s_ip6; + + s_ip6 = nm_connection_get_setting_ip6_config(c); + g_assert(s_ip6); + g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_AUTO); +} + +static void +verify_ipv6_disabled(NMConnection *c) +{ + NMSettingIPConfig *s_ip6; + + s_ip6 = nm_connection_get_setting_ip6_config(c); + g_assert(s_ip6); + g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6), + ==, + NM_SETTING_IP6_CONFIG_METHOD_DISABLED); +} + +static int +count_nm_conn(NMConnection **connections) +{ + int cnt; + + for (cnt = 0; connections && *connections; connections++, cnt++) + ; + + return cnt; +} + +static void +free_connections(NMConnection **connections) +{ + NMConnection **c; + + for (c = connections; c && *c; c++) + g_object_unref(*c); + g_free(connections); +} + +static void +test_read_nbft_ipv4_static(void) +{ + NMConnection **nbft_connections; + NMConnection *connection; + const char *expected_mac_address; + gs_free char *hostname = NULL; + + nbft_connections = nmi_nbft_reader_parse(TEST_INITRD_DIR "/nbft-ipv4-static", &hostname); + g_assert_nonnull(hostname); + g_assert_cmpint(count_nm_conn(nbft_connections), ==, 6); + + /* NBFT-multi HFI 1 */ + expected_mac_address = "52:54:00:72:c5:ae"; + connection = find_connection_for_mac(nbft_connections, expected_mac_address, 0); + verify_connection(connection, expected_mac_address, 0); + verify_ipv4(connection, "192.168.122.158", 24, "192.168.122.1"); + verify_ipv6_disabled(connection); + + /* NBFT-multi HFI 2 */ + expected_mac_address = "52:54:00:72:c5:af"; + connection = find_connection_for_mac(nbft_connections, expected_mac_address, 0); + verify_connection(connection, expected_mac_address, 0); + verify_ipv4_dhcp(connection); + verify_ipv6_disabled(connection); + + /* NBFT-Dell.PowerEdge.R660-fw1.5.5-mpath+discovery HFI 1 */ + expected_mac_address = "00:62:0b:cb:eb:70"; + connection = find_connection_for_mac(nbft_connections, expected_mac_address, 0); + verify_connection(connection, expected_mac_address, 0); + verify_ipv4(connection, "172.18.240.1", 24, NULL); + verify_ipv6_disabled(connection); + + /* NBFT-Dell.PowerEdge.R660-fw1.5.5-mpath+discovery HFI 2 */ + expected_mac_address = "00:62:0b:cb:eb:71"; + connection = find_connection_for_mac(nbft_connections, expected_mac_address, 0); + verify_connection(connection, expected_mac_address, 0); + verify_ipv4(connection, "172.18.230.2", 24, NULL); + verify_ipv6_disabled(connection); + + /* NBFT-rhpoc */ + expected_mac_address = "ea:eb:d3:58:89:58"; + connection = find_connection_for_mac(nbft_connections, expected_mac_address, 0); + verify_connection(connection, expected_mac_address, 0); + verify_ipv4(connection, "192.168.101.30", 24, NULL); + verify_ipv6_disabled(connection); + + /* NBFT-static-ipv4 */ + expected_mac_address = "52:54:00:b8:19:b9"; + connection = find_connection_for_mac(nbft_connections, expected_mac_address, 0); + verify_connection(connection, expected_mac_address, 0); + verify_ipv4(connection, "192.168.49.50", 24, NULL); + verify_ipv6_disabled(connection); + + free_connections(nbft_connections); +} + +static void +test_read_nbft_ipv4_dhcp(void) +{ + NMConnection **nbft_connections; + NMConnection *connection; + const char *expected_mac_address; + gs_free char *hostname = NULL; + + nbft_connections = nmi_nbft_reader_parse(TEST_INITRD_DIR "/nbft-ipv4-dhcp", &hostname); + g_assert_nonnull(hostname); + g_assert_cmpint(count_nm_conn(nbft_connections), ==, 2); + + /* NBFT-dhcp-ipv4 */ + expected_mac_address = "52:54:00:b8:19:b9"; + connection = find_connection_for_mac(nbft_connections, expected_mac_address, 0); + verify_connection(connection, expected_mac_address, 0); + verify_ipv4_dhcp(connection); + verify_ipv6_disabled(connection); + + /* NBFT-Dell.PowerEdge.R760 */ + expected_mac_address = "b0:26:28:e8:7c:0e"; + connection = find_connection_for_mac(nbft_connections, expected_mac_address, 0); + verify_connection(connection, expected_mac_address, 0); + verify_ipv4_dhcp(connection); + verify_ipv6_disabled(connection); + + free_connections(nbft_connections); +} + +static void +test_read_nbft_ipv6_static(void) +{ + NMConnection **nbft_connections; + NMConnection *connection; + const char *expected_mac_address; + gs_free char *hostname = NULL; + + nbft_connections = nmi_nbft_reader_parse(TEST_INITRD_DIR "/nbft-ipv6-static", &hostname); + g_assert_nonnull(hostname); + g_assert_cmpint(count_nm_conn(nbft_connections), ==, 1); + + /* NBFT-static-ipv6 */ + expected_mac_address = "52:54:00:9e:20:1a"; + connection = find_connection_for_mac(nbft_connections, expected_mac_address, 0); + verify_connection(connection, expected_mac_address, 0); + verify_ipv6(connection, "fd09:9a46:b5c1:1fe::10", 64, NULL); + verify_ipv4_disabled(connection); + + free_connections(nbft_connections); +} + +static void +test_read_nbft_ipv6_auto(void) +{ + NMConnection **nbft_connections; + NMConnection *connection; + const char *expected_mac_address; + gs_free char *hostname = NULL; + + nbft_connections = nmi_nbft_reader_parse(TEST_INITRD_DIR "/nbft-ipv6-auto", &hostname); + g_assert_nonnull(hostname); + g_assert_cmpint(count_nm_conn(nbft_connections), ==, 3); + + /* NBFT-auto-ipv6 */ + expected_mac_address = "52:54:00:9e:20:1a"; + connection = find_connection_for_mac(nbft_connections, expected_mac_address, 0); + verify_connection(connection, expected_mac_address, 0); + verify_ipv6(connection, "fd09:9a46:b5c1:1ff:5054:ff:fe9e:201a", 64, NULL); + verify_ipv4_disabled(connection); + + /* NBFT-dhcp-ipv6 */ + expected_mac_address = "52:54:00:b8:19:b9"; + connection = find_connection_for_mac(nbft_connections, expected_mac_address, 0); + verify_connection(connection, expected_mac_address, 0); + verify_ipv6_auto(connection); + verify_ipv4_disabled(connection); + + /* NBFT-ipv6-noip+disc */ + expected_mac_address = "40:a6:b7:c0:8a:c9"; + connection = find_connection_for_mac(nbft_connections, expected_mac_address, 0); + verify_connection(connection, expected_mac_address, 0); + verify_ipv6_auto(connection); + verify_ipv4_disabled(connection); + + free_connections(nbft_connections); +} + +static void +test_read_nbft_vlan(void) +{ + NMConnection **nbft_connections; + NMConnection *connection; + const char *expected_mac_address; + gs_free char *hostname = NULL; + + nbft_connections = nmi_nbft_reader_parse(TEST_INITRD_DIR "/nbft-vlan", &hostname); + g_assert_cmpstr(hostname, ==, NULL); + g_assert_cmpint(count_nm_conn(nbft_connections), ==, 4); + + /* NBFT-qemu-vlans-incomplete HFI 1 */ + expected_mac_address = "52:54:00:72:c5:ae"; + connection = find_connection_for_mac(nbft_connections, expected_mac_address, 0); + verify_connection(connection, expected_mac_address, 0); + verify_ipv4(connection, "192.168.122.158", 24, "192.168.122.1"); + verify_ipv6_disabled(connection); + + /* NBFT-qemu-vlans-incomplete HFI 2 */ + expected_mac_address = "52:54:00:72:c5:af"; + connection = find_connection_for_mac(nbft_connections, expected_mac_address, 0); + verify_connection(connection, expected_mac_address, 0); + verify_ipv4_disabled(connection); + verify_ipv6_disabled(connection); + + /* NBFT-qemu-vlans-incomplete HFI 2 VLAN 11 */ + expected_mac_address = "52:54:00:72:c5:af"; + connection = find_connection_for_mac(nbft_connections, expected_mac_address, 11); + verify_connection(connection, expected_mac_address, 11); + verify_ipv4(connection, "192.168.124.58", 24, NULL); + verify_ipv6_disabled(connection); + + /* NBFT-qemu-vlans-incomplete HFI 2 VLAN 12 */ + expected_mac_address = "52:54:00:72:c5:af"; + connection = find_connection_for_mac(nbft_connections, expected_mac_address, 12); + verify_connection(connection, expected_mac_address, 12); + verify_ipv4(connection, "192.168.125.58", 24, NULL); + verify_ipv6_disabled(connection); + + free_connections(nbft_connections); +} + +NMTST_DEFINE(); + +int +main(int argc, char **argv) +{ + nmtst_init_assert_logging(&argc, &argv, "INFO", "DEFAULT"); + + g_test_add_func("/initrd/nbft/ipv4-static", test_read_nbft_ipv4_static); + g_test_add_func("/initrd/nbft/ipv4-dhcp", test_read_nbft_ipv4_dhcp); + g_test_add_func("/initrd/nbft/ipv6-static", test_read_nbft_ipv6_static); + g_test_add_func("/initrd/nbft/ipv6-auto", test_read_nbft_ipv6_auto); + g_test_add_func("/initrd/nbft/vlan", test_read_nbft_vlan); + + return g_test_run(); +}