From 35ec247ac2dc4611cd3c9e99e0fcea0cf0d97415 Mon Sep 17 00:00:00 2001 From: Samuel Mendoza-Jonas Date: Fri, 30 Nov 2018 16:55:43 +1100 Subject: [PATCH] utils: Add helper to send mailbox request A simple script to set, display, and clear a BMC's boot initiator mailbox. Signed-off-by: Samuel Mendoza-Jonas --- utils/ipmi-mailbox-config.py | 166 +++++++++++++++++++++++++++++++++++ 1 file changed, 166 insertions(+) create mode 100755 utils/ipmi-mailbox-config.py diff --git a/utils/ipmi-mailbox-config.py b/utils/ipmi-mailbox-config.py new file mode 100755 index 0000000..1b57ebb --- /dev/null +++ b/utils/ipmi-mailbox-config.py @@ -0,0 +1,166 @@ +#!/usr/bin/env python3 + +import argparse +import subprocess + +def send_block_read_command(hostname, username, password, index, dry_run): + + if hostname is None and dry_run: + hostname = "" + + cmd = "ipmitool -I lanplus -H " + hostname + if username is not None: + cmd = cmd + " -U " + username + if password is not None: + cmd = cmd + " -P " + password + + # chassis netfn, get-sys-boot-options, parameter 7, set-sel, block-sel + cmd = cmd + " raw 0x00 0x09 0x07 " + hex(index) + " 0x00 " + + print(cmd) + if not dry_run: + rc = subprocess.call(cmd, shell=True) + if rc != 0: + print("Command returned error: {}".format(rc)) + +def send_block_command(hostname, username, password, block, index, dry_run): + + if hostname is None and dry_run: + hostname = "" + + cmd = "ipmitool -I lanplus -H " + hostname + if username is not None: + cmd = cmd + " -U " + username + if password is not None: + cmd = cmd + " -P " + password + + # chassis netfn, set-sys-boot-options, parameter 7, set-sel, block-sel + cmd = cmd + " raw 0x00 0x08 0x07 " + hex(index) + " " + block + + print(cmd) + if not dry_run: + rc = subprocess.call(cmd, shell=True) + if rc != 0: + print("Command returned error: {}".format(rc)) + +def construct_buffer(config, max_blocks): + + # Add IBM's IANA prefix + raw = bytes([0x02, 0x00, 0x00]) + config.encode('ascii') + + n_blocks = int(len(raw) / 16) + if len(raw) % 16 != 0: + n_blocks += 1 + + if n_blocks > 255: + print("ERROR: buffer would require {} blocks".format(n_blocks) + + " which is more than hypothetically possible (255)") + return None + + if n_blocks > max_blocks: + print("ERROR: buffer would require {} blocks".format(n_blocks) + + " which is more than max_blocks ({})".format(max_blocks)) + return None + + if n_blocks > 5: + print("Warning: buffer would require {} blocks".format(n_blocks) + + "which is more than some BMCs support") + + blocks = [] + rem = len(raw) + for i in range(n_blocks): + block = "" + if rem >= 16: + last = 16 + else: + last = rem + + for j in range(16): + if j < last: + block += "{:#02x} ".format(raw[i * 16 + j]) + else: + # Pad out to 16 bytes + block += "0x00 " + + + blocks.append(block) + rem -= last + + if n_blocks < max_blocks: + for i in range(max_blocks - n_blocks): + blocks.append("0x00 0x00 0x00 0x00 " + + "0x00 0x00 0x00 0x00 " + + "0x00 0x00 0x00 0x00 " + + "0x00 0x00 0x00 0x00") + + return blocks + +def construct_empty_buffer(max_blocks): + + blocks = [] + for i in range(max_blocks): + blocks.append("0x00 0x00 0x00 0x00 " + + "0x00 0x00 0x00 0x00 " + + "0x00 0x00 0x00 0x00 " + + "0x00 0x00 0x00 0x00") + + return blocks + +def main(): + + parser = argparse.ArgumentParser() + parser.add_argument("-b", "--bmc-hostname") + parser.add_argument("-u", "--username") + parser.add_argument("-p", "--password") + parser.add_argument("-n", "--dry-run", action="store_true") + parser.add_argument("-c", "--config") + parser.add_argument("-x", "--clear", action="store_true") + parser.add_argument("-d", "--dump", action="store_true") + parser.add_argument("-m", "--max-blocks") + + args = parser.parse_args() + + if not args.dry_run and args.bmc_hostname is None: + print("No hostname specified!") + return -1 + + if args.config and args.clear: + print("Can't specify --config and --clear together") + return -1 + + if args.max_blocks: + n_blocks = int(args.max_blocks) + else: + n_blocks = 16 + + + if args.config or args.clear: + if args.config: + blocks = construct_buffer(args.config, int(args.max_blocks)) + if args.clear: + blocks = construct_empty_buffer(int(args.max_blocks)) + if blocks is None: + print("Failed to construct buffer") + return -1 + + print("{} blocks to send".format(len(blocks))) + print("---------------------------------------") + for i in range(len(blocks)): + try: + send_block_command(args.bmc_hostname, args.username, args.password, + blocks[i], i, args.dry_run) + except Exception as e: + print(e) + print("Error sending block {}".format(i)) + return -1 + i += 1 + + if args.dump: + print("\nReading {} blocks".format(n_blocks)) + print("---------------------------------------") + for i in range(n_blocks): + send_block_read_command(args.bmc_hostname, args.username, + args.password, i, args.dry_run) + +if __name__ == "__main__": + main() -- 2.39.2