# BST-TIMEOUT: 600 # MEASURED against an x86-64 control of the identical SRCREV: # # ~55 cases, every one a short-lived fork of a 212 KB binary, # # no daemon, no sleep and no unbounded command. exec is a # # fresh wasm module instantiation here (~2-3 s), so the wall # # clock is dominated by ~55 spawns; 600 leaves a multiple of # # headroom over that on a loaded host. # # mctp 1.1 (meta-openembedded/meta-networking recipes-support/mctp, SRCREV # a591ad88) -- Code Construct's userland control tool for the kernel MCTP stack, # the wire between a host and its management controllers. One installed program, # /usr/bin/mctp. # # --------------------------------------------------------------------------- # THIS KERNEL HAS NO MCTP, AND THAT IS THE ASSERTION RATHER THAN AN OBSTACLE. # # net/mctp/ is built by obj-$(CONFIG_MCTP) and arch/wasm32/configs/wasm32_defconfig # carries no CONFIG_MCTP line at all -- it sets CONFIG_NET, CONFIG_INET and # CONFIG_UNIX and stops there. So there is no AF_MCTP protocol family, no MCTP # address family handler registered with rtnetlink, and no MCTP-capable link. # # WHAT MUST BE SAID FIRST, BECAUSE THE PACKAGE'S NAME MISLEADS: THE INSTALLED # BINARY NEVER OPENS AN AF_MCTP SOCKET. mctp.c reaches the kernel only through # AF_NETLINK/NETLINK_ROUTE (mctp-netlink.c:68). The AF_MCTP sockets in this # source tree belong to mctp-req and mctp-echo, and upstream's own meson.build # gives neither `install: true', so neither reaches any image. mctpd, which does # open one, is built only when pkg-config finds libsystemd and is absent here. # The ticket's "a socket(AF_MCTP, ...) that fails must produce a diagnosed error, # never a crash on the returned -1" therefore has no subject on this image, and # no case below claims to test it. What IS tested is the equivalent statement # about the surface that does exist, which is the netlink one. # # --------------------------------------------------------------------------- # HOW A NO-MCTP KERNEL ANSWERS, AND WHY THAT IS A CLEAN RESULT RATHER THAN AN # ERROR PATH. # # mctp_nl_new() opens AF_NETLINK/NETLINK_ROUTE and then dumps RTM_GETLINK with # ifi_family = AF_MCTP (mctp-netlink.c:739). rtnetlink_rcv_msg falls back to # PF_UNSPEC when no handler is registered for a family (net/core/rtnetlink.c), # and rtnl_valid_dump_ifinfo_req validates ifi_pad/type/flags/change/index but # NOT ifi_family -- so the dump succeeds and returns the ordinary link list. # parse_getlink_dump then skips every interface that carries no IFLA_AF_SPEC / # AF_MCTP nest (mctp-netlink.c:"Skip non-MCTP interfaces"), which here is all of # them. The linkmap comes back EMPTY and mctp_nl_new SUCCEEDS. # # Everything follows from that empty linkmap: # # * `mctp link show' prints NOTHING and exits 0: display_ifinfo returns # silently for an interface with no AF_MCTP nest, and every interface here # is in that class. # * `address show' and `route show' exit 0 and print ONE LINE PER RECORD THE # KERNEL RETURNED, every one of them reading `dev (null)'. This is the one # thing in this file the control run got wrong, and it was corrected from # the batch-1949 verify rather than reasoned: RTM_GETADDR and RTM_GETROUTE # have no AF_MCTP handler either, so rtnetlink_rcv_msg falls back to the # PF_UNSPEC one -- which for these two is rtnl_dump_all, and it answers with # the OTHER families' records (inet, inet6). cmd_addr_show's display_ifaddr # (mctp.c:248) and display_route (mctp.c:338) print every record they are # handed WITHOUT looking at ifa_family / rtm_family -- the family check at # mctp-netlink.c:831 is in fill_local_addrs, which the show path does not # go through. So an inet address is printed as an MCTP one, with IFA_LOCAL # read as a u8 EID (4 bytes, so the u8 getter declines and eid stays 0) and # ifa_index resolved in the EMPTY linkmap, which is where `dev (null)' # comes from. `dev (null)' on every line IS the assertion that no MCTP # object exists; the line count is not ours to predict and is not asserted. # * `neigh show' prints nothing here, but for a weaker reason than the link # case: RTM_GETNEIGH takes the same PF_UNSPEC fallback, and the answer is # empty because the guest's neighbour table is, not because anything # filtered. It is scored as `no line names a device' with the other two. # * every command that NAMES a device fails on the LINK LOOKUP -- `mctp: # invalid device ', or `Unknown interface' from the address object -- # before any MCTP-specific netlink message is built. Not on the parse, and # not on a socket. # # THAT SECOND SHAPE IS MEASURED, NOT REASONED. The control host has CONFIG_MCTP=y, # so it cannot show an empty linkmap; but an interface that is present and NOT # MCTP-capable takes the identical code path, and driving the control against # such an interface (enp4s0) produced exactly the messages and statuses asserted # below. On this image every interface is in that class. # # --------------------------------------------------------------------------- # THE FILE IS SCORED IN THREE GROUPS, AND SAYS WHICH IS WHICH. # # OFFLINE -- the surface reached BEFORE mctp_nl_new() is called at all: no # arguments, -h/--help, an unrecognised option, and an unknown # command. main() handles each of these and returns without ever # touching the kernel. Asserted for real, string and status. # # PROBE -- one bounded run that establishes whether the netlink path works # here, and reports the linkmap it built. Everything below it # depends on mctp_nl_new() having succeeded, so a failure there is # reported ONCE, under its own case, rather than as forty reds each # naming a symptom. # # NETLINK -- everything that runs after mctp_nl_new(): the empty shows, the # device lookups, and ALL of the argument parsing. That last one is # a structural fact worth stating -- `mctp address add' with too # few arguments is diagnosed inside cmd_addr, which main() reaches # only after the netlink object exists, so even the malformed # fixtures are not an offline surface on this tool. # # --------------------------------------------------------------------------- # TWO COMMANDS ARE NEVER RUN HERE, DELIBERATELY. # # `mctp monitor' is `while (1) { mctp_nl_recv_all(...) }' (mctp.c:1196). It # does not return. Only `mctp monitor help' is driven, which prints its one # usage line and returns 255 before the loop. # # `mctp link serial ' sets the N_MCTP line discipline on the tty and then # calls pause() (mctp.c:cmd_link_serial), which blocks for ever. Only the two # forms that cannot reach it are driven: no device at all, which returns before # the open, and a path that does not exist, which err()s at the open. A real # tty is never passed. # # Between them those are the only ways this file could wedge the guest, and # neither is reachable from any case below. # # --------------------------------------------------------------------------- # WHAT AN x86-64 CONTROL RUN CAN AND CANNOT SAY ABOUT THIS FILE. # # The file was validated end to end against a control build of the identical # SRCREV before it shipped -- 81 cases, 69 green. The 12 reds are ONE cause and # not defects: the control host is built CONFIG_MCTP=y, so `lo' IS an MCTP link # there and the linkmap is not empty. Those thirteen are exactly the cases whose # subject is the ABSENCE of MCTP, and they are the cases a control cannot be an # oracle for: # # linkmap-empty, show-link-empty, link-bare-empty, link-show-lo, link-set-lo, # addr-show-lo, addr-add-lo, addr-del-lo, route-add-lo, route-del-lo, # neigh-add-lo, neigh-del-lo # # show-link-rc passes there for the wrong reason -- the show succeeded and # printed lo -- which is why the empty-output half of each show is a separate # case rather than folded into the status one. Everything else # -- the whole offline surface, every usage string, every unknown-object message # and every malformed-argument refusal -- was measured on that run and is a # transcription of what the binary printed, not of what the source suggested. # # AND THAT LAST SENTENCE WAS TOO CONFIDENT: THE FIRST TARGET RUN FALSIFIED SEVEN # OF THESE CASES. They are recorded here rather than quietly corrected, because # the way they were wrong is the useful part -- each was a real transcription of # a real control run, and each was a fact about a CONFIG_MCTP=y host that reads # as a fact about the tool: # # show-address-empty, show-route-empty, prefix-addr, prefix-a -- expected no # output. The control's linkmap was not empty, so its dumps were answered by # the MCTP handler and were about MCTP. Here there is no handler, the request # falls back to rtnl_dump_all, and the tool prints the inet records it is # handed. Corrected to `no line names a device' (section 4a). # # addr-eid-over, addr-eid-alpha, addr-eid-negative -- expected `invalid # address', and asserted in as many words that the EID is parsed BEFORE the # device is looked up. The source says the reverse, and the control could not # show it: its link lookup SUCCEEDED, so the parse was reached and the true # ordering was invisible. Corrected, renamed -on-link, in section 4e. # # The pattern in all seven is one thing: a case whose answer depends on the # linkmap being non-empty, in a file whose whole subject is an empty linkmap. A # control on a host with the feature can only be an oracle for the surface that # does not touch the feature, and the boundary is wider than it looks. # # ONE CONSEQUENCE FOR A FUTURE KERNEL. `link set lo up' and `address add 8 dev # lo' are the two cases here that would CHANGE state on a machine where lo is a # real MCTP link. On this image they cannot: they are refused at the link # lookup, which is the assertion. An image that grows CONFIG_MCTP turns them red # -- correctly, because the premise this whole file rests on would have changed # -- and whoever reads that red should retire the pair rather than re-point them. # # --------------------------------------------------------------------------- # THERE IS NO VERSION OUTPUT, SO THE VERSION IS ASSERTED THROUGH THE MANIFEST. # # mctp's getopt_long table is {help, verbose} and nothing in the source prints a # version string; `mctp --version' is simply an unrecognised option. The recipe's # ${PN}-tests package therefore carries install-manifest with `version ${PV}', # generated from ${D}, and that is where the ticket's "the version the recipe # pins" is read back from. . "$BST_LIB" S=mctp R=${BST_CC_ROOT:-} M=$R/usr/bin/mctp LIBEXEC=$R/usr/libexec/mctp-tests MAN=$LIBEXEC/install-manifest W=${TMPDIR:-/tmp}/bst-$S.$$ mkdir -p "$W" 2>/dev/null require "$M" $S/present # ck : ok iff exits AND its # combined output contains the literal . bst.sh has check_out (rc 0 plus # a substring) and check_rc (a status alone); almost every assertion in this file # needs BOTH halves against a NON-ZERO status, because that is the shape of every # diagnosed refusal mctp makes. Passing an empty needle asserts the status only. ck() { _ck_id=$1; _ck_want=$2; _ck_need=$3; shift 3 _ck_out=$("$@" 2>&1); _ck_rc=$? case "$_ck_out" in *"$_ck_need"*) _ck_hit=1 ;; *) _ck_hit=0 ;; esac if bst_execfail "$_ck_out"; then bst_unrun "$_ck_id" "$_ck_out" elif [ "$_ck_rc" -eq "$_ck_want" ] && [ "$_ck_hit" -eq 1 ]; then bst_ok "$_ck_id" else bst_notok "$_ck_id" "rc=$_ck_rc want=$_ck_want want:'$_ck_need' got:'$(_bst_1line "$_ck_out")'" fi } # --- section 1: the -tests package arrived, and the image equals its manifest - check $S/manifest-present test -f "$MAN" if [ ! -f "$MAN" ]; then bst_notok $S/manifest "no $MAN: mctp-tests is not on this image, so nothing below has a subject" rm -rf "$W" 2>/dev/null exit 0 fi # bst_local first: the manifest is read with `while ... done < file', which must # stay in this shell to keep the variables it sets, and a top-level stdin # redirect from the virtiofs root makes dup2(2) return 513 -- ash treats that as # fatal and exits, taking every case below with it while the run still reads as a # clean pass (brintos/linux#73). MANL=$(bst_local "$MAN") check_eq $S/manifest-root / "$(LC_ALL=C awk '$1=="root"{print $2; exit}' "$MANL")" # THE PORT'S VERSION, and the only place on this image it can be read: the tool # prints none. `version' is ${PV} and `srcrev' is the commit meta-networking # pins, so a recipe bump that moved either without anyone noticing lands here. check_eq $S/manifest-version 1.1 \ "$(LC_ALL=C awk '$1=="version"{print $2; exit}' "$MANL")" check_eq $S/manifest-srcrev a591ad885aa28f113cb45870b2fd5bce48378d6f \ "$(LC_ALL=C awk '$1=="srcrev"{print $2; exit}' "$MANL")" # EXACT, not a floor. The recipe installs exactly one file and asserts that over # ${D} too, so a bump that added a second is expected to move this deliberately. count=$(LC_ALL=C awk '$1=="count"{print $2; exit}' "$MANL") check_eq $S/manifest-count 1 "$count" # The count agrees with the body it heads. A header drifted from its own entries # would otherwise satisfy every per-file case below while covering nothing. check_eq $S/manifest-count-agrees "$count" \ "$(LC_ALL=C awk 'NR>4' "$MANL" | LC_ALL=C awk 'END{print NR+0}')" if ! command -v sha256sum >/dev/null 2>&1 || ! command -v stat >/dev/null 2>&1; then bst_skip $S/per-file "no sha256sum and/or stat on this image; the manifest cannot be checked against the tree" else LC_ALL=C awk 'NR>4' "$MANL" > "$W/body" while IFS=' ' read -r mode sha rel; do [ -n "$rel" ] || continue if [ ! -f "$R$rel" ]; then bst_notok $S/installed:$rel "manifest names it, image does not have it" continue fi bst_ok $S/installed:$rel check_eq $S/mode:$rel "$mode" "$(stat -c %a "$R$rel")" check_eq $S/digest:$rel "$sha" "$(sha256sum "$R$rel" | cut -d' ' -f1)" done < "$W/body" fi # Against 0755 rather than against the manifest: the pair above is self-consistent # by construction, both sides descending from the same do_install, so it would # stay green if the recipe started installing this world-writable. check_eq $S/mode-is-0755 755 "$(stat -c %a "$M" 2>/dev/null)" # mctpd is gated off with systemd absent from DISTRO_FEATURES, and its three unit # files and D-Bus policy go with it. Asserted on the image as well as over ${D}: # a distro that grew the feature would ship a DAEMON here, which is a different # package from the one this suite drives and a different ticket. check $S/no-mctpd test ! -e $R/usr/sbin/mctpd check $S/no-dbus-conf test ! -e $R/usr/share/dbus-1/system.d/mctpd.conf # mctp-req and mctp-echo are built by meson and never installed by it -- neither # executable() carries `install: true'. Asserted so that a recipe which started # installing them is caught: they are the two programs that DO open AF_MCTP, and # they would be unexercised binaries arriving with no suite behind them. check $S/no-mctp-req test ! -e $R/usr/bin/mctp-req check $S/no-mctp-echo test ! -e $R/usr/bin/mctp-echo # --- section 2: OFFLINE -- the surface reached before mctp_nl_new() ------------ # # main() handles each of these and returns without opening a socket, so they are # the only assertions in this file that hold whatever the kernel does. Each # expected string and status was read off an x86-64 control build of SRCREV # a591ad88, never off the source. # No arguments: the top-level usage, and 255. Not 0, and not 1 -- main() returns # print_usage()'s 255 directly here, which is a different path from the one a # subcommand's `help' takes below. ck $S/usage-no-args 255 "usage: mctp [args]" "$M" ck $S/usage-lists-cmds 255 "Commands: link, address, route, neighbour, monitor, help" "$M" # -h and --help print every object's usage and return 255 from main() directly. ck $S/opt-h-status 255 "mctp link show [ifname]" "$M" -h ck $S/opt-help-status 255 "mctp address add dev " "$M" --help ck $S/opt-help-route 255 "mctp route add via [mtu ]" "$M" --help ck $S/opt-help-neigh 255 "mctp neigh add dev lladdr " "$M" --help ck $S/opt-help-monitor 255 "mctp monitor" "$M" --help # An unrecognised option: getopt_long's own complaint, then the usage, then 255. # The needle omits the program-name prefix on purpose -- getopt prints argv[0] # verbatim, so it is `/usr/bin/mctp:' here and `./mctp:' on the control, while # warnx() elsewhere uses the basename. Asserting the prefix would make the case # depend on how the suite spelled the path. ck $S/opt-unknown 255 "unrecognized option '--bogus'" "$M" --bogus ck $S/opt-unknown-usage 255 "usage: mctp [args]" "$M" --bogus # An unknown COMMAND is errx(EXIT_FAILURE, ...) from main() before the netlink # object is made: status 1, not 255, and NO usage line. The ticket asked for "an # unknown object and an unknown command each rejected with a usage line and a # non-zero status"; the status holds, the usage line does not, and the second # case records that difference rather than papering over it. ck $S/cmd-unknown 1 "mctp: no such command 'zzz'" "$M" zzz if [ -n "$("$M" zzz 2>&1 | LC_ALL=C grep -F 'usage: mctp')" ]; then bst_notok $S/cmd-unknown-no-usage "an unknown command printed a usage line; upstream errx()s without one" else bst_ok $S/cmd-unknown-no-usage fi # --- section 3: the PROBE ------------------------------------------------------ # # One bounded run that decides whether anything below has a subject. # # `-v link show nosuchif0' is chosen because it is the CHEAPEST complete exercise # of mctp_nl_new(): it opens the netlink socket, dumps RTM_GETLINK, dumps # RTM_GETADDR, prints the linkmap it built under -v, and then fails on the # unknown interface BEFORE issuing the second dump that `-v link show' alone # would hexdump every attribute of. Measured at 72 bytes of output on the # control, against ~100 KB for the bare `-v link show'. # # bst_probe bounds it. If the netlink path wedges rather than answering, this is # the one place it can, and the bound turns a hung suite -- which would take the # whole batch image's verify down with it -- into a single named red. # The probe runs mctp through `sh -c ...; exit 0'. bst_probe reports `not ok' on # any non-zero status, and THIS COMMAND EXITS 1 BY DESIGN -- the interface it # names does not exist. Without the wrapper the case would ship a permanent red # that says nothing, which is exactly the unattributable red this file must not # produce. What the case asserts is the one thing that matters here: that # mctp_nl_new() RETURNED, inside the bound. The status it returned with is # asserted separately, on the probe's own transcript, below. PRB=$W/probe bst_probe $S/netlink-object-bounded "$PRB" 30 \ sh -c '"$1" -v link show nosuchif0; exit 0' sh "$M" prc=$? PRBOUT="$(cat "$PRB" "$PRB".err 2>/dev/null)" # 124 is bst_probe's overrun status; anything else means it came back. if [ "$prc" -eq 124 ]; then NETLINK=wedged elif LC_ALL=C printf '%s' "$PRBOUT" | LC_ALL=C grep -qF 'Error creating netlink object'; then NETLINK=refused elif LC_ALL=C printf '%s' "$PRBOUT" | LC_ALL=C grep -qF 'linkmap'; then NETLINK=ok else NETLINK=unknown fi case "$NETLINK" in ok) bst_ok $S/netlink-object ;; wedged) bst_notok $S/netlink-object "mctp_nl_new() did not return within 30s; the rtnetlink dump does not answer on this kernel" ;; refused) bst_notok $S/netlink-object "mctp_nl_new() failed: $(_bst_1line "$PRBOUT")" ;; *) bst_notok $S/netlink-object "mctp_nl_new() neither printed a linkmap nor refused: $(_bst_1line "$PRBOUT")" ;; esac # THE POSITIVE STATEMENT OF THE TICKET'S PREMISE. Under -v, mctp_nl_linkmap_dump # prints `linkmap' and then one indented line per MCTP-capable interface. On a # kernel with no MCTP that header stands alone, and that is a far stronger # assertion than "the shows printed nothing": it is the tool reporting, from its # own parsed view of the kernel, that the count is zero. if [ "$NETLINK" = ok ]; then # The probe's STDOUT is the linkmap dump and nothing else -- mctp_nl_linkmap_dump # printf()s there, while the refusal below goes to stderr through warnx. So on # a kernel with no MCTP the whole of stdout is the one word `linkmap', and any # entry the tool found would appear as an extra indented line and fail this. check_eq $S/linkmap-empty "linkmap" "$(cat "$PRB" 2>/dev/null)" # And the same run's refusal is on the LINK, which is the ticket's # "fail on the link rather than on the parse", asserted here on the probe's # own transcript so it costs no second exec. if LC_ALL=C grep -qF 'invalid device nosuchif0' "$PRB".err; then bst_ok $S/link-show-absent-fails-on-link else bst_notok $S/link-show-absent-fails-on-link "want 'invalid device nosuchif0' on stderr, got:'$(_bst_1line "$(cat "$PRB".err 2>/dev/null)")'" fi else bst_notok $S/linkmap-empty "not measured: $S/netlink-object is $NETLINK" bst_notok $S/link-show-absent-fails-on-link "not measured: $S/netlink-object is $NETLINK" fi # --- section 4: NETLINK -- everything after mctp_nl_new() ---------------------- # # Skipped as a block, with the probe's reason, when the netlink object could not # be made. That is a skip and not forty reds: the subject of each case below is # the tool's behaviour GIVEN a netlink object, and without one there is nothing # for them to be about. The single red is $S/netlink-object above, which names # the cause once. if [ "$NETLINK" != ok ]; then bst_skip $S/netlink-cases "mctp_nl_new() is $NETLINK; see $S/netlink-object, which carries the cause" rm -rf "$W" 2>/dev/null exit 0 fi # 4a. THE SHOWS. Every one exits 0 -- a kernel with no MCTP is not an error # condition -- and none of them names an MCTP object. What "names no object" # looks like differs by object, and the difference is the rtnetlink fallback # described in the header: `link show' is genuinely empty because mctp filters # the link dump itself, while `address show' and `route show' are answered by # rtnl_dump_all with other families' records and print one `dev (null)' line # per record. # # So the address and route assertion is `not one line names a device', not `not # one line'. That is the invariant with a subject: an EID is only reachable # through a link, so a record that resolves to no link is not an MCTP object # however the kernel came to emit it. It is also the only stable form -- the # line count is the guest's inet/inet6 address and route count, which is no # business of this suite's and would make the case flap on an image that gained # an interface. # # no_dev: the output with every `dev (null)' line removed. Empty means nothing # named a device. A warning printed to stdout would not read as `dev (null)' # either, so this still fails the case the exact-empty form was defending. for obj in link address route neigh; do out=$("$M" $obj show 2>/dev/null); rc=$? if [ "$rc" -ne 0 ]; then bst_notok $S/show-$obj-rc "rc=$rc, want 0" else bst_ok $S/show-$obj-rc fi case "$obj" in link|neigh) check_eq $S/show-$obj-empty "" "$out" ;; *) no_dev=$(printf '%s\n' "$out" | LC_ALL=C grep -v 'dev (null)' | LC_ALL=C tr -d ' \n') check_eq $S/show-$obj-empty "" "$no_dev" ;; esac done # `mctp link' with no subcommand is cmd_link_show(0, NULL) -- the same answer as # `link show', by a different path through cmd_link. ck $S/link-bare-rc 0 "" "$M" link check_eq $S/link-bare-empty "" "$("$M" link 2>/dev/null)" # Prefix matching is upstream's dispatch (strncmp over strlen(argv[1])), which is # how `addr' and `neigh' reach `address' and `neighbour' at all. Asserted, because # every abbreviation the ticket uses depends on it. # # Asserted as `the abbreviation produces what the full command produced', taken # from this same boot, rather than against a literal. That is the actual claim # -- these cases are about DISPATCH, not about what address show prints -- and # it is what survived the correction above: comparing to "" tested dispatch only # for as long as the full command's own answer happened to be empty, and when it # stopped being empty all three abbreviation cases went red without anything # having gone wrong with dispatch. addr_show=$("$M" address show 2>/dev/null) neigh_show=$("$M" neighbour show 2>/dev/null) check_eq $S/prefix-addr "$addr_show" "$("$M" addr show 2>/dev/null)" check_eq $S/prefix-a "$addr_show" "$("$M" a show 2>/dev/null)" check_eq $S/prefix-neigh "$neigh_show" "$("$M" neigh show 2>/dev/null)" # 4b. EVERY COMMAND THAT NAMES A DEVICE FAILS ON THE LINK LOOKUP. # # This is the ticket's central assertion. On this image no interface carries an # AF_MCTP nest, so the linkmap holds none of them and mctp_nl_ifindex_byname # returns 0 -- a diagnosed refusal with a fixed status, reached before any # MCTP-specific netlink message is built and without a socket of that family ever # being asked for. `lo' is used as the named device because it certainly EXISTS # on this image: the point is that a real interface is still not an MCTP link, # which is a sharper statement than naming one that is absent outright. ck $S/link-show-lo 1 "mctp: invalid device lo" "$M" link show lo ck $S/link-set-lo 1 "mctp: invalid device lo" "$M" link set lo up ck $S/addr-show-lo 1 "mctp: Unknown interface 'lo'" "$M" address show lo ck $S/addr-add-lo 1 "mctp: invalid device lo" "$M" address add 8 dev lo ck $S/addr-del-lo 1 "mctp: invalid device lo" "$M" address del 8 dev lo ck $S/route-add-lo 1 "mctp: invalid device lo" "$M" route add 9 via lo ck $S/route-del-lo 1 "mctp: invalid device lo" "$M" route del 9 via lo ck $S/neigh-add-lo 1 "mctp: invalid device lo" "$M" neigh add 9 dev lo lladdr 1d ck $S/neigh-del-lo 1 "mctp: invalid device lo" "$M" neigh del 9 dev lo # A name that does not exist at all takes the same path, and must fail on the # LINK rather than on the argument parse -- the two are distinguishable here # precisely because the message names the device. ck $S/link-show-absent 1 "mctp: invalid device nosuchif0" "$M" link show nosuchif0 ck $S/addr-add-absent 1 "mctp: invalid device nosuchif0" "$M" address add 8 dev nosuchif0 # 4c. THE PER-OBJECT USAGE. Reached only after mctp_nl_new(), which is why it is # here and not in section 2. Each returns 255 from its cmd_*, and main() then # maps any non-zero to EXIT_FAILURE -- so the STATUS IS 1, not the 255 the # top-level -h gives. That asymmetry is upstream's (`TODO: pass 255 out as a # program exit code', mctp.c:cmd_help) and is asserted as what it is. ck $S/help-link 1 "mctp link serial " "$M" link help ck $S/help-address 1 "mctp address del dev " "$M" address help ck $S/help-route 1 "mctp route del via " "$M" route help ck $S/help-neigh 1 'syntax is for example "1d" or "aa:bb:cc:11:22:33"' "$M" neigh help ck $S/help-monitor 1 "mctp monitor" "$M" monitor help ck $S/help-cmd 1 "mctp link show [ifname]" "$M" help # 4d. UNKNOWN OBJECTS -- the ticket's "an unknown object rejected". Each object # diagnoses its own, and the messages are NOT uniform: link capitalises, address # does not, and neigh reports itself as `route' because cmd_neigh reuses # cmd_route's string. That last one is an upstream cosmetic defect; it is # asserted as it stands, because a suite that asserted the tidy message would go # red on correct software. ck $S/unknown-link-cmd 1 "mctp: Unknown link command 'bogus'" "$M" link bogus ck $S/unknown-addr-cmd 1 "mctp: unknown address command 'bogus'" "$M" address bogus ck $S/unknown-route-cmd 1 "mctp: unknown route command 'bogus'" "$M" route bogus ck $S/unknown-neigh-cmd 1 "mctp: unknown route command 'bogus'" "$M" neigh bogus # 4e. THE ADDRESS AND ROUTE ARGUMENTS, WELL-FORMED AND MALFORMED. # # The well-formed ones are the `dev lo' cases in 4b: they parse completely and # then fail on the link, which is what proves the parse accepted them. These are # the malformed ones, and each must be refused for its OWN reason rather than # collapsing into one generic complaint. # Too few arguments: cmd_addr's own arity check, before any value is read. ck $S/addr-add-noargs 1 "mctp: add: invalid command line arguments" "$M" address add ck $S/addr-add-noeid 1 "mctp: add: invalid command line arguments" "$M" address add 8 ck $S/addr-add-nodev 1 "mctp: add: invalid command line arguments" "$M" address add 8 dev # THE ORDERING IS THE ASSERTION, AND IT IS THE OPPOSITE OF WHAT THE CONTROL RUN # SUGGESTED. cmd_addr_addremove (mctp.c) checks the `dev' keyword, then calls # mctp_nl_ifindex_byname on the link, and only then parse_uint32 on the EID. So # on THIS image the EID validator inside the address object is UNREACHABLE: the # empty linkmap refuses `lo' first, whatever was written where the EID goes, and # the answer is `invalid device lo' for all three. The control host printed # `invalid address' only because CONFIG_MCTP=y made its `lo' a real MCTP link, # so the lookup succeeded there and the parse was reached -- which looks # identical to "the EID is checked first" and is not it. Measured on batch-1949. # # This is worth three cases rather than one because the input is malformed in # three different ways -- out of range, non-numeric, negative -- and the claim is # that NONE of them is diagnosed here, not that one is not. The EID validator # itself is still covered on this image: route's path parses the EID before the # device, which is what $S/route-eid-over and $S/route-eid-alpha below assert. ck $S/addr-eid-over-on-link 1 "mctp: invalid device lo" "$M" address add 999 dev lo ck $S/addr-eid-alpha-on-link 1 "mctp: invalid device lo" "$M" address add abc dev lo ck $S/addr-eid-negative-on-link 1 "mctp: invalid device lo" "$M" address add -1 dev lo # The `dev' keyword itself, misspelled: a distinct complaint again. ck $S/addr-bad-devspec 1 "mctp: invalid dev spec" "$M" address add 8 xyz lo # route's arity and value checks, which are separate code from address's and # produce different text for the same class of mistake. ck $S/route-add-noargs 1 "mctp: add: invalid command line arguments" "$M" route add ck $S/route-add-noeid 1 "mctp: add: invalid command line arguments" "$M" route add 9 ck $S/route-add-novia 1 "mctp: add: invalid command line arguments" "$M" route add 9 via ck $S/route-eid-over 1 "mctp: Bad eid" "$M" route add 999 via lo ck $S/route-eid-alpha 1 "mctp: add: invalid command line arguments" "$M" route add abc via lo ck $S/route-bad-mtu 1 "mctp: add: invalid command line arguments" "$M" route add 9 via lo mtu abc # neigh's lladdr, which is parsed before the device lookup the same way address's # eid is. ck $S/neigh-bad-lladdr 1 "mctp: invalid lladdr zz:zz" "$M" neigh add 9 dev lo lladdr zz:zz # link set with no arguments at all, and link show with too many. ck $S/link-set-noargs 1 "mctp: Bad arguments to 'link set'" "$M" link set ck $S/link-show-toomany 1 "mctp: Bad arguments to 'link show'" "$M" link show a b c # 4f. link serial, in the only two forms that cannot reach pause(). # # No device: cmd_link_serial's arity check, which returns 255 before the open -- # and main() maps that to 1, as in 4c. ck $S/serial-nodev 1 "mctp link serial: no device specified" "$M" link serial # A path that does not exist: err(EXIT_FAILURE) at the open. A REAL tty is never # passed, here or anywhere in this file: setting N_MCTP on one is followed by # pause(), and the suite would never return. ck $S/serial-absent 1 "mctp: Can't open tty /nonexistent/tty0" "$M" link serial /nonexistent/tty0 rm -rf "$W" 2>/dev/null