qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/2] hw/ipmi/ipmi_bmc_sim: Get/set fake LAN config
@ 2025-10-28 18:01 Yunpeng Yang
  2025-10-28 18:01 ` [PATCH 1/2] hw/ipmi/ipmi_bmc_sim: Support getting fake LAN channel config Yunpeng Yang
                   ` (2 more replies)
  0 siblings, 3 replies; 7+ messages in thread
From: Yunpeng Yang @ 2025-10-28 18:01 UTC (permalink / raw)
  To: minyard@acm.org
  Cc: farosas@suse.de, lvivier@redhat.com, pbonzini@redhat.com,
	qemu-devel@nongnu.org, Mark Cave-Ayland, corey@minyard.net,
	Jonathan Davies, cornelia.huck@de.ibm.com

Support for a fake LAN channel is added to the device `ipmi_bmc_sim`.
Although there is no real LAN channel, some testing processes which
require interactions with BMC LAN channel will become easier.

There's another device `ipmi_bmc_extern` which works together with some
external BMC simulator, e.g., `ipmi_sim`. More comprehensive BMC
simulation can be achieved with `ipmi_bmc_extern`. However,
`ipmi_bmc_sim` is more light-weight and is built into QEMU.

Yunpeng Yang (2):
  hw/ipmi/ipmi_bmc_sim: Support getting fake LAN channel config
  hw/ipmi/ipmi_bmc_sim: Support setting fake LAN channel config

 hw/ipmi/ipmi_bmc_sim.c      | 407 +++++++++++++++++++++++++++++++++++-
 include/hw/ipmi/ipmi.h      |   1 +
 qemu-options.hx             |  26 +++
 tests/qtest/ipmi-kcs-test.c | 143 +++++++++++++
 4 files changed, 567 insertions(+), 10 deletions(-)

-- 
2.43.7



^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH 1/2] hw/ipmi/ipmi_bmc_sim: Support getting fake LAN channel config
  2025-10-28 18:01 [PATCH 0/2] hw/ipmi/ipmi_bmc_sim: Get/set fake LAN config Yunpeng Yang
@ 2025-10-28 18:01 ` Yunpeng Yang
  2025-12-01 20:18   ` Philippe Mathieu-Daudé
  2025-10-28 18:01 ` [PATCH 2/2] hw/ipmi/ipmi_bmc_sim: Support setting " Yunpeng Yang
  2025-11-24 20:54 ` [PATCH 0/2] hw/ipmi/ipmi_bmc_sim: Get/set fake LAN config Corey Minyard
  2 siblings, 1 reply; 7+ messages in thread
From: Yunpeng Yang @ 2025-10-28 18:01 UTC (permalink / raw)
  To: minyard@acm.org
  Cc: farosas@suse.de, lvivier@redhat.com, pbonzini@redhat.com,
	qemu-devel@nongnu.org, Mark Cave-Ayland, corey@minyard.net,
	Jonathan Davies, cornelia.huck@de.ibm.com

The following IPMI commands are added or modified to support getting
fake LAN channel configurations from the `ipmi_bmc_sim` device:
* Get Channel Access;
* Get Channel Info Command;
* Get LAN Configuration Parameters.

The fake LAN channel configurations can be specified from QEMU
commandline options for device `ipmi_bmc_sim`. Inside the guest OS, the
configurations can be retrieved from the device using some IPMI tools,
e.g., `ipmitool lan print`.
Note, there is not a real LAN channel. The fake LAN channel is suitable
for testing purposes.

Signed-off-by: Yunpeng Yang <yunpeng.yang@nutanix.com>
---
 hw/ipmi/ipmi_bmc_sim.c      | 297 ++++++++++++++++++++++++++++++++++--
 include/hw/ipmi/ipmi.h      |   1 +
 qemu-options.hx             |  26 ++++
 tests/qtest/ipmi-kcs-test.c |  60 ++++++++
 4 files changed, 374 insertions(+), 10 deletions(-)

diff --git a/hw/ipmi/ipmi_bmc_sim.c b/hw/ipmi/ipmi_bmc_sim.c
index 04e1dcd0e7..2ead46ee55 100644
--- a/hw/ipmi/ipmi_bmc_sim.c
+++ b/hw/ipmi/ipmi_bmc_sim.c
@@ -27,11 +27,13 @@
 #include "qemu/timer.h"
 #include "hw/ipmi/ipmi.h"
 #include "qemu/error-report.h"
+#include "qapi/error.h"
 #include "qemu/module.h"
 #include "hw/loader.h"
 #include "hw/qdev-properties.h"
 #include "hw/qdev-properties-system.h"
 #include "migration/vmstate.h"
+#include "net/net.h"
 
 #define IPMI_NETFN_CHASSIS            0x00
 
@@ -70,6 +72,7 @@
 #define IPMI_CMD_GET_MSG                  0x33
 #define IPMI_CMD_SEND_MSG                 0x34
 #define IPMI_CMD_READ_EVT_MSG_BUF         0x35
+#define IPMI_CMD_GET_CHANNEL_ACCESS       0x41
 #define IPMI_CMD_GET_CHANNEL_INFO         0x42
 
 #define IPMI_NETFN_STORAGE            0x0a
@@ -101,6 +104,10 @@
 #define IPMI_CMD_GET_SEL_TIME             0x48
 #define IPMI_CMD_SET_SEL_TIME             0x49
 
+#define IPMI_NETFN_TRANSPORT          0x0c
+
+#define IPMI_CMD_GET_LAN_CONFIG           0x02
+
 
 /* Same as a timespec struct. */
 struct ipmi_time {
@@ -170,6 +177,23 @@ typedef struct IPMISensor {
 #define MAX_SENSORS 20
 #define IPMI_WATCHDOG_SENSOR 0
 
+#define NBYTES_IP  4
+#define NBYTES_MAC 6
+
+typedef struct IPMILan {
+    uint8_t channel;
+    uint8_t ipaddr[NBYTES_IP];
+    uint8_t ipsrc;
+    MACAddr macaddr;
+    uint8_t netmask[NBYTES_IP];
+    uint8_t defgw_ipaddr[NBYTES_IP];
+    MACAddr defgw_macaddr;
+
+    char *arg_ipaddr;
+    char *arg_netmask;
+    char *arg_defgw_ipaddr;
+} IPMILan;
+
 #define MAX_NETFNS 64
 
 typedef struct IPMIRcvBufEntry {
@@ -215,6 +239,7 @@ struct IPMIBmcSim {
     IPMIFru fru;
     IPMISensor sensors[MAX_SENSORS];
     char *sdr_filename;
+    IPMILan lan;
 
     /* Odd netfns are for responses, so we only need the even ones. */
     const IPMINetfn *netfns[MAX_NETFNS / 2];
@@ -265,6 +290,36 @@ struct IPMIBmcSim {
 #define IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN      2
 #define IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE     3
 
+#define IPMI_CHANNEL_IMPLEMENTATION_MIN    0x1
+#define IPMI_CHANNEL_IMPLEMENTATION_MAX    0xb
+#define IPMI_CHANNEL_IS_IMPLEMENTATION_SPECIFIC(c) \
+    (IPMI_CHANNEL_IMPLEMENTATION_MIN <= (c) && \
+     (c) <= IPMI_CHANNEL_IMPLEMENTATION_MAX)
+
+#define IPMI_BMC_CHANNEL_IS_LAN(ibs, c) \
+    ((ibs)->lan.channel != 0 && (ibs)->lan.channel == (c))
+
+#define IPMI_BMC_LAN_CFG_CC_PARAM_NOT_SUPPORTED    0x80
+
+#define IPMI_BMC_LAN_CFG_PARAM_SET_IN_PROGRESS        0x00
+#define IPMI_BMC_LAN_CFG_PARAM_AUTH_TYPE_SUPPORT      0x01
+#define IPMI_BMC_LAN_CFG_PARAM_AUTH_TYPE_ENABLES      0x02
+#define IPMI_BMC_LAN_CFG_PARAM_IP_ADDR                0x03
+#define IPMI_BMC_LAN_CFG_PARAM_IP_ADDR_SOURCE         0x04
+#define IPMI_BMC_LAN_CFG_PARAM_MAC_ADDR               0x05
+#define IPMI_BMC_LAN_CFG_PARAM_SUBNET_MASK            0x06
+#define IPMI_BMC_LAN_CFG_PARAM_IPV4_HDR_PARAMS        0x07
+#define IPMI_BMC_LAN_CFG_PARAM_DEFAULT_GW_IP_ADDR     0x0c
+#define IPMI_BMC_LAN_CFG_PARAM_DEFAULT_GW_MAC_ADDR    0x0d
+#define IPMI_BMC_LAN_CFG_PARAM_BACKUP_GW_ADDR         0x0e
+#define IPMI_BMC_LAN_CFG_PARAM_BACKUP_GW_MAC_ADDR     0x0f
+#define IPMI_BMC_LAN_CFG_PARAM_COMMUNITY_STRING       0x10
+#define IPMI_BMC_LAN_CFG_PARAM_NUM_DESTINATIONS       0x11
+
+#define IPMI_BMC_LAN_CFG_PARAMETER_REVISION    0x11
+
+#define IPMI_BMC_LAN_CFG_IS_VALID_IP_SOURCE(v)    (0x0 <= (v) && (v) <= 0x4)
+
 #define RSP_BUFFER_INITIALIZER { }
 
 static inline void rsp_buffer_pushmore(RspBuffer *rsp, uint8_t *bytes,
@@ -1231,6 +1286,25 @@ static void get_watchdog_timer(IPMIBmcSim *ibs,
     }
 }
 
+static void get_channel_access(IPMIBmcSim *ibs,
+                               uint8_t *cmd, unsigned int cmd_len,
+                               RspBuffer *rsp)
+{
+    uint8_t channel = cmd[2] & 0xf;
+
+    if (channel == IPMI_CHANNEL_IPMB || channel == IPMI_CHANNEL_SYSTEM ||
+        IPMI_BMC_CHANNEL_IS_LAN(ibs, channel)) {
+        /* alerting disabled */
+        /* per message authentication disabled */
+        /* user level authentication disabled */
+        /* channel always available */
+        rsp_buffer_push(rsp, 0x20 | 0x10 | 0x08 | 0x02);
+        rsp_buffer_push(rsp, 0x04);  /* privilege limit: ADMINISTRATOR */
+    } else {
+        rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
+    }
+}
+
 static void get_channel_info(IPMIBmcSim *ibs,
                              uint8_t *cmd, unsigned int cmd_len,
                              RspBuffer *rsp)
@@ -1240,29 +1314,29 @@ static void get_channel_info(IPMIBmcSim *ibs,
     IPMIFwInfo info = {};
     uint8_t ch = cmd[2] & 0x0f;
 
-    /* Only define channel 0h (IPMB) and Fh (system interface) */
-
     if (ch == 0x0e) { /* "This channel" */
         ch = IPMI_CHANNEL_SYSTEM;
     }
     rsp_buffer_push(rsp, ch);
 
-    if (ch != IPMI_CHANNEL_IPMB && ch != IPMI_CHANNEL_SYSTEM) {
-        /* Not a supported channel */
-        rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
-        return;
-    }
-
     if (k->get_fwinfo) {
         k->get_fwinfo(s, &info);
     }
 
+    /* Only define channel 0h (IPMB), LAN, and Fh (system interface) */
     if (ch == IPMI_CHANNEL_IPMB) {
         rsp_buffer_push(rsp, IPMI_CHANNEL_MEDIUM_IPMB);
         rsp_buffer_push(rsp, IPMI_CHANNEL_PROTOCOL_IPMB);
-    } else { /* IPMI_CHANNEL_SYSTEM */
+    } else if (IPMI_BMC_CHANNEL_IS_LAN(ibs, ch)) {
+        rsp_buffer_push(rsp, IPMI_CHANNEL_MEDIUM_802_3_LAN);
+        rsp_buffer_push(rsp, IPMI_CHANNEL_PROTOCOL_IPMB);
+    } else if (ch == IPMI_CHANNEL_SYSTEM) {
         rsp_buffer_push(rsp, IPMI_CHANNEL_MEDIUM_SYSTEM);
         rsp_buffer_push(rsp, info.ipmi_channel_protocol);
+    } else {
+        /* Not a supported channel */
+        rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
+        return;
     }
 
     rsp_buffer_push(rsp, 0x00); /* Session-less */
@@ -2045,6 +2119,140 @@ static void set_sensor_reading(IPMIBmcSim *ibs,
     }
 }
 
+static inline bool is_valid_netmask(const uint8_t *netmask)
+{
+    uint32_t mask = netmask[3];
+    uint32_t inverted;
+
+    mask |= (uint32_t) netmask[2] << 8;
+    mask |= (uint32_t) netmask[1] << 16;
+    mask |= (uint32_t) netmask[0] << 24;
+    inverted = ~mask;
+    return mask != 0 && (inverted & (inverted + 1)) == 0;
+}
+
+/*
+ * Request data (from cmd[2] to cmd[5] inclusive):
+ * bytes   meaning
+ *    1    [bit 7] revision only flag, [bits 3:0] channel number
+ *    2    parameter selector
+ *    3    set selector
+ *    4    block selector
+ */
+static void get_lan_config(IPMIBmcSim *ibs,
+                           uint8_t *cmd, unsigned int cmd_len,
+                           RspBuffer *rsp)
+{
+    uint8_t channel;
+
+    if (ibs->lan.channel == 0) {
+        /* LAN channel disabled. Fail as if this command were not defined. */
+        rsp_buffer_set_error(rsp, IPMI_CC_INVALID_CMD);
+        return;
+    }
+    if (cmd_len < 6) {
+        rsp_buffer_set_error(rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID);
+        return;
+    }
+    channel = cmd[2] & 0xf;
+
+    rsp_buffer_push(rsp, IPMI_BMC_LAN_CFG_PARAMETER_REVISION);
+    if (cmd[2] & 0x80) {
+        /* The requester only requests parameter revision, not the parameter */
+        return;
+    }
+    if (!IPMI_BMC_CHANNEL_IS_LAN(ibs, channel)) {
+        rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
+        return;
+    }
+
+    switch (cmd[3]) {
+    case IPMI_BMC_LAN_CFG_PARAM_SET_IN_PROGRESS:
+        rsp_buffer_push(rsp, 0x0);  /* set complete */
+        break;
+
+    case IPMI_BMC_LAN_CFG_PARAM_AUTH_TYPE_SUPPORT:
+        rsp_buffer_push(rsp, 0x01); /* Authentication type "none" supported */
+        break;
+
+    case IPMI_BMC_LAN_CFG_PARAM_AUTH_TYPE_ENABLES:
+        /* Only authentication type "none" enabled */
+        rsp_buffer_push(rsp, 0x01); /* for privilege level "Callback" */
+        rsp_buffer_push(rsp, 0x01); /* for privilege level "User" */
+        rsp_buffer_push(rsp, 0x01); /* for privilege level "Operator" */
+        rsp_buffer_push(rsp, 0x01); /* for privilege level "Administrator" */
+        rsp_buffer_push(rsp, 0x01); /* for privilege level "OEM" */
+        break;
+
+    case IPMI_BMC_LAN_CFG_PARAM_IP_ADDR:
+        rsp_buffer_pushmore(rsp, ibs->lan.ipaddr, NBYTES_IP);
+        break;
+
+    case IPMI_BMC_LAN_CFG_PARAM_IP_ADDR_SOURCE:
+        rsp_buffer_push(rsp, ibs->lan.ipsrc);
+        break;
+
+    case IPMI_BMC_LAN_CFG_PARAM_MAC_ADDR:
+        rsp_buffer_pushmore(rsp, ibs->lan.macaddr.a, NBYTES_MAC);
+        break;
+
+    case IPMI_BMC_LAN_CFG_PARAM_SUBNET_MASK:
+        rsp_buffer_pushmore(rsp, ibs->lan.netmask, NBYTES_IP);
+        break;
+
+    case IPMI_BMC_LAN_CFG_PARAM_IPV4_HDR_PARAMS:
+        /* TTL 0x40 */
+        rsp_buffer_push(rsp, 0x40);
+        /* don't fragment */
+        rsp_buffer_push(rsp, 0x40);
+        /* precedence 0x0, minimize delay */
+        rsp_buffer_push(rsp, 0x10);
+        break;
+
+    case IPMI_BMC_LAN_CFG_PARAM_DEFAULT_GW_IP_ADDR:
+        rsp_buffer_pushmore(rsp, ibs->lan.defgw_ipaddr, NBYTES_IP);
+        break;
+
+    case IPMI_BMC_LAN_CFG_PARAM_DEFAULT_GW_MAC_ADDR:
+        rsp_buffer_pushmore(rsp, ibs->lan.defgw_macaddr.a, NBYTES_MAC);
+        break;
+
+    case IPMI_BMC_LAN_CFG_PARAM_BACKUP_GW_ADDR:
+        /* 0.0.0.0 */
+        rsp_buffer_push(rsp, 0x00);
+        rsp_buffer_push(rsp, 0x00);
+        rsp_buffer_push(rsp, 0x00);
+        rsp_buffer_push(rsp, 0x00);
+        break;
+
+    case IPMI_BMC_LAN_CFG_PARAM_BACKUP_GW_MAC_ADDR:
+        /* 00:00:00:00:00:00 */
+        rsp_buffer_push(rsp, 0x00);
+        rsp_buffer_push(rsp, 0x00);
+        rsp_buffer_push(rsp, 0x00);
+        rsp_buffer_push(rsp, 0x00);
+        rsp_buffer_push(rsp, 0x00);
+        rsp_buffer_push(rsp, 0x00);
+        break;
+
+    case IPMI_BMC_LAN_CFG_PARAM_COMMUNITY_STRING:
+        {
+            static uint8_t community_str[18] = "public";
+
+            rsp_buffer_pushmore(rsp, community_str, sizeof(community_str));
+        }
+        break;
+
+    case IPMI_BMC_LAN_CFG_PARAM_NUM_DESTINATIONS:
+        rsp_buffer_push(rsp, 0x00); /* LAN Alerting not supported */
+        break;
+
+    default:
+        rsp_buffer_set_error(rsp, IPMI_BMC_LAN_CFG_CC_PARAM_NOT_SUPPORTED);
+        return;
+    };
+}
+
 static const IPMICmdHandler chassis_cmds[] = {
     [IPMI_CMD_GET_CHASSIS_CAPABILITIES] = { chassis_capabilities },
     [IPMI_CMD_GET_CHASSIS_STATUS] = { chassis_status },
@@ -2089,6 +2297,7 @@ static const IPMICmdHandler app_cmds[] = {
     [IPMI_CMD_RESET_WATCHDOG_TIMER] = { reset_watchdog_timer },
     [IPMI_CMD_SET_WATCHDOG_TIMER] = { set_watchdog_timer, 8 },
     [IPMI_CMD_GET_WATCHDOG_TIMER] = { get_watchdog_timer },
+    [IPMI_CMD_GET_CHANNEL_ACCESS] = { get_channel_access, 4 },
     [IPMI_CMD_GET_CHANNEL_INFO] = { get_channel_info, 3 },
 };
 static const IPMINetfn app_netfn = {
@@ -2119,12 +2328,22 @@ static const IPMINetfn storage_netfn = {
     .cmd_handlers = storage_cmds
 };
 
+static const IPMICmdHandler transport_cmds[] = {
+    [IPMI_CMD_GET_LAN_CONFIG] = { get_lan_config },
+};
+static const IPMINetfn transport_netfn = {
+    .cmd_nums = ARRAY_SIZE(transport_cmds),
+    .cmd_handlers = transport_cmds
+};
+
+
 static void register_cmds(IPMIBmcSim *s)
 {
     ipmi_sim_register_netfn(s, IPMI_NETFN_CHASSIS, &chassis_netfn);
     ipmi_sim_register_netfn(s, IPMI_NETFN_SENSOR_EVENT, &sensor_event_netfn);
     ipmi_sim_register_netfn(s, IPMI_NETFN_APP, &app_netfn);
     ipmi_sim_register_netfn(s, IPMI_NETFN_STORAGE, &storage_netfn);
+    ipmi_sim_register_netfn(s, IPMI_NETFN_TRANSPORT, &transport_netfn);
 }
 
 static uint8_t init_sdrs[] = {
@@ -2176,7 +2395,7 @@ static void ipmi_sdr_init(IPMIBmcSim *ibs)
 
 static const VMStateDescription vmstate_ipmi_sim = {
     .name = TYPE_IPMI_BMC_SIMULATOR,
-    .version_id = 1,
+    .version_id = 2,
     .minimum_version_id = 1,
     .fields = (const VMStateField[]) {
         VMSTATE_UINT8(bmc_global_enables, IPMIBmcSim),
@@ -2198,6 +2417,13 @@ static const VMStateDescription vmstate_ipmi_sim = {
         VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].deassert_states,
                        IPMIBmcSim),
         VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].assert_enable, IPMIBmcSim),
+        VMSTATE_UINT8_V(lan.channel, IPMIBmcSim, 2),
+        VMSTATE_UINT8_ARRAY_V(lan.ipaddr, IPMIBmcSim, NBYTES_IP, 2),
+        VMSTATE_UINT8_V(lan.ipsrc, IPMIBmcSim, 2),
+        VMSTATE_UINT8_ARRAY_V(lan.macaddr.a, IPMIBmcSim, NBYTES_MAC, 2),
+        VMSTATE_UINT8_ARRAY_V(lan.netmask, IPMIBmcSim, NBYTES_IP, 2),
+        VMSTATE_UINT8_ARRAY_V(lan.defgw_ipaddr, IPMIBmcSim, NBYTES_IP, 2),
+        VMSTATE_UINT8_ARRAY_V(lan.defgw_macaddr.a, IPMIBmcSim, NBYTES_MAC, 2),
         VMSTATE_END_OF_LIST()
     }
 };
@@ -2232,6 +2458,47 @@ out:
     fru->nentries = size / fru->areasize;
 }
 
+static void ipmi_lan_init(IPMILan *lan, Error **errp)
+{
+    struct in_addr ip;
+
+    /*
+     * `lan->channel` can be either 0 (meaning LAN channel disabled) or
+     * a valid IPMI implementation-specific channel.
+     */
+    if (lan->channel != 0 &&
+        !IPMI_CHANNEL_IS_IMPLEMENTATION_SPECIFIC(lan->channel)) {
+        error_setg(errp, "invalid LAN channel %d", lan->channel);
+        return;
+    }
+    if (lan->arg_ipaddr) {
+        if (inet_pton(AF_INET, lan->arg_ipaddr, &ip) != 1) {
+            error_setg(errp, "invalid ip address '%s'", lan->arg_ipaddr);
+            return;
+        }
+        memcpy(lan->ipaddr, &ip.s_addr, NBYTES_IP);
+    }
+    if (!IPMI_BMC_LAN_CFG_IS_VALID_IP_SOURCE(lan->ipsrc)) {
+        error_setg(errp, "invalid ip source %d", lan->ipsrc);
+        return;
+    }
+    if (lan->arg_netmask) {
+        if (inet_pton(AF_INET, lan->arg_netmask, &ip) != 1 ||
+            !is_valid_netmask((const uint8_t *) &ip.s_addr)) {
+            error_setg(errp, "invalid subnet mask '%s'", lan->arg_netmask);
+            return;
+        }
+        memcpy(lan->netmask, &ip.s_addr, NBYTES_IP);
+    }
+    if (lan->arg_defgw_ipaddr) {
+        if (inet_pton(AF_INET, lan->arg_defgw_ipaddr, &ip) != 1) {
+            error_setg(errp, "invalid ip address '%s'", lan->arg_defgw_ipaddr);
+            return;
+        }
+        memcpy(lan->defgw_ipaddr, &ip.s_addr, NBYTES_IP);
+    }
+}
+
 static void ipmi_sim_realize(DeviceState *dev, Error **errp)
 {
     IPMIBmc *b = IPMI_BMC(dev);
@@ -2259,6 +2526,9 @@ static void ipmi_sim_realize(DeviceState *dev, Error **errp)
     ibs->acpi_power_state[1] = 0;
 
     ipmi_init_sensors_from_sdrs(ibs);
+
+    ipmi_lan_init(&ibs->lan, errp);
+
     register_cmds(ibs);
 
     ibs->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, ipmi_timeout, ibs);
@@ -2276,6 +2546,13 @@ static const Property ipmi_sim_properties[] = {
     DEFINE_PROP_UINT32("mfg_id", IPMIBmcSim, mfg_id, 0),
     DEFINE_PROP_UINT16("product_id", IPMIBmcSim, product_id, 0),
     DEFINE_PROP_UUID_NODEFAULT("guid", IPMIBmcSim, uuid),
+    DEFINE_PROP_UINT8("lan.channel", IPMIBmcSim, lan.channel, 0),
+    DEFINE_PROP_STRING("lan.ipaddr", IPMIBmcSim, lan.arg_ipaddr),
+    DEFINE_PROP_UINT8("lan.ipsrc", IPMIBmcSim, lan.ipsrc, 0),
+    DEFINE_PROP_MACADDR("lan.macaddr", IPMIBmcSim, lan.macaddr),
+    DEFINE_PROP_STRING("lan.netmask", IPMIBmcSim, lan.arg_netmask),
+    DEFINE_PROP_STRING("lan.defgw_ipaddr", IPMIBmcSim, lan.arg_defgw_ipaddr),
+    DEFINE_PROP_MACADDR("lan.defgw_macaddr", IPMIBmcSim, lan.defgw_macaddr),
 };
 
 static void ipmi_sim_class_init(ObjectClass *oc, const void *data)
diff --git a/include/hw/ipmi/ipmi.h b/include/hw/ipmi/ipmi.h
index cd581aa134..3435d84178 100644
--- a/include/hw/ipmi/ipmi.h
+++ b/include/hw/ipmi/ipmi.h
@@ -45,6 +45,7 @@ enum ipmi_op {
 #define IPMI_CHANNEL_IPMB                0x00
 #define IPMI_CHANNEL_SYSTEM              0x0f
 #define IPMI_CHANNEL_MEDIUM_IPMB         0x01
+#define IPMI_CHANNEL_MEDIUM_802_3_LAN    0x04
 #define IPMI_CHANNEL_MEDIUM_SYSTEM       0x0c
 #define IPMI_CHANNEL_PROTOCOL_IPMB       0x01
 #define IPMI_CHANNEL_PROTOCOL_KCS        0x05
diff --git a/qemu-options.hx b/qemu-options.hx
index 0223ceffeb..100226d84b 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -1142,6 +1142,32 @@ SRST
         is set, get "Get GUID" command to the BMC will return it.
         Otherwise "Get GUID" will return an error.
 
+    ``lan.channel=val``
+        channel number of the fake LAN channel. It can be 0 or any
+        integer from 0x1 to 0xb inclusive. If set to 0, the LAN channel
+        is disabled, otherwise the LAN channel is enabled at the
+        specified channel number. The default is 0.
+
+    ``lan.ipaddr=addr``
+        the ipv4 address of the BMC LAN channel.
+
+    ``lan.ipsrc=val``
+        the ipv4 address source of the BMC LAN channel. It can be 0
+        (unspecified source), 1 (static address), 2 (DHCP), 3 (BIOS or
+        system software), or 4 (other source). The default is 0.
+
+    ``lan.macaddr=mac``
+        the mac address of the BMC LAN channel.
+
+    ``lan.netmask=mask``
+        the ipv4 subnet mask for the BMC LAN channel.
+
+    ``lan.defgw_ipaddr=addr``
+        the default gateway ipv4 address for the BMC LAN channel.
+
+    ``lan.defgw_macaddr=mac``
+        the default gateway mac address for the BMC LAN channel.
+
 ``-device ipmi-bmc-extern,id=id,chardev=id[,slave_addr=val]``
     Add a connection to an external IPMI BMC simulator. Instead of
     locally emulating the BMC like the above item, instead connect to an
diff --git a/tests/qtest/ipmi-kcs-test.c b/tests/qtest/ipmi-kcs-test.c
index 3186c6ad64..d0a207477e 100644
--- a/tests/qtest/ipmi-kcs-test.c
+++ b/tests/qtest/ipmi-kcs-test.c
@@ -262,6 +262,62 @@ static void test_enable_irq(void)
     kcs_ints_enabled = 1;
 }
 
+
+static uint8_t get_channel_access_cmd[] = { 0x18, 0x41, 0x01, 0x40 };
+static uint8_t get_channel_access_rsp[] = { 0x1c, 0x41, 0x00, 0x3a, 0x04 };
+
+/*
+ * Get channel access
+ */
+static void test_kcs_channel_access(void)
+{
+    uint8_t rsp[20];
+    unsigned int rsplen = sizeof(rsp);
+
+    kcs_cmd(get_channel_access_cmd, sizeof(get_channel_access_cmd),
+            rsp, &rsplen);
+    g_assert(rsplen == sizeof(get_channel_access_rsp));
+    g_assert(memcmp(get_channel_access_rsp, rsp, rsplen) == 0);
+}
+
+
+static uint8_t get_channel_info_cmd[] = { 0x18, 0x42, 0x01 };
+static uint8_t get_channel_info_rsp[] = { 0x1c, 0x42, 0x00, 0x01, 0x04, 0x01,
+                                          0x00, 0xf2, 0x1b, 0x00, 0x00, 0x00 };
+
+/*
+ * Get channel info
+ */
+static void test_kcs_channel_info(void)
+{
+    uint8_t rsp[20];
+    unsigned int rsplen = sizeof(rsp);
+
+    kcs_cmd(get_channel_info_cmd, sizeof(get_channel_info_cmd), rsp, &rsplen);
+    g_assert(rsplen == sizeof(get_channel_info_rsp));
+    g_assert(memcmp(get_channel_info_rsp, rsp, rsplen) == 0);
+}
+
+
+/* get ip address (specified in cmdline): 10.0.0.2 */
+static uint8_t get_ipaddr_cmd[] = { 0x30, 0x02, 0x01, 0x03, 0x00, 0x00 };
+static uint8_t get_ipaddr_rsp[] = { 0x34, 0x02, 0x00, 0x11,
+                                    0x0a, 0x00, 0x00, 0x02 };
+
+/*
+ * Get LAN configurations
+ */
+static void test_kcs_lan_get(void)
+{
+    uint8_t rsp[20];
+    unsigned int rsplen = sizeof(rsp);
+
+    kcs_cmd(get_ipaddr_cmd, sizeof(get_ipaddr_cmd), rsp, &rsplen);
+    g_assert(rsplen == sizeof(get_ipaddr_rsp));
+    g_assert(memcmp(get_ipaddr_rsp, rsp, rsplen) == 0);
+}
+
+
 int main(int argc, char **argv)
 {
     char *cmdline;
@@ -271,6 +327,7 @@ int main(int argc, char **argv)
     g_test_init(&argc, &argv, NULL);
 
     cmdline = g_strdup_printf("-device ipmi-bmc-sim,id=bmc0"
+                                       ",lan.channel=1,lan.ipaddr=10.0.0.2"
                               " -device isa-ipmi-kcs,bmc=bmc0");
     qtest_start(cmdline);
     g_free(cmdline);
@@ -280,6 +337,9 @@ int main(int argc, char **argv)
     qtest_add_func("/ipmi/local/kcs_enable_irq", test_enable_irq);
     qtest_add_func("/ipmi/local/kcs_base_irq", test_kcs_base);
     qtest_add_func("/ipmi/local/kcs_abort_irq", test_kcs_abort);
+    qtest_add_func("/ipmi/local/kcs_channel_access", test_kcs_channel_access);
+    qtest_add_func("/ipmi/local/kcs_channel_info", test_kcs_channel_info);
+    qtest_add_func("/ipmi/local/kcs_lan_get", test_kcs_lan_get);
     ret = g_test_run();
     qtest_quit(global_qtest);
 
-- 
2.43.7



^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 2/2] hw/ipmi/ipmi_bmc_sim: Support setting fake LAN channel config
  2025-10-28 18:01 [PATCH 0/2] hw/ipmi/ipmi_bmc_sim: Get/set fake LAN config Yunpeng Yang
  2025-10-28 18:01 ` [PATCH 1/2] hw/ipmi/ipmi_bmc_sim: Support getting fake LAN channel config Yunpeng Yang
@ 2025-10-28 18:01 ` Yunpeng Yang
  2025-11-24 20:54 ` [PATCH 0/2] hw/ipmi/ipmi_bmc_sim: Get/set fake LAN config Corey Minyard
  2 siblings, 0 replies; 7+ messages in thread
From: Yunpeng Yang @ 2025-10-28 18:01 UTC (permalink / raw)
  To: minyard@acm.org
  Cc: farosas@suse.de, lvivier@redhat.com, pbonzini@redhat.com,
	qemu-devel@nongnu.org, Mark Cave-Ayland, corey@minyard.net,
	Jonathan Davies, cornelia.huck@de.ibm.com

The "Set LAN Configuration Parameters" IPMI command is added to the
`ipmi_bmc_sim` device to support dynamically setting fake LAN channel
configurations. With the fake LAN channel enabled, inside the guest OS,
tools such as `ipmitool` can be used to modify the configurations.

Signed-off-by: Yunpeng Yang <yunpeng.yang@nutanix.com>
---
 hw/ipmi/ipmi_bmc_sim.c      | 110 ++++++++++++++++++++++++++++++++++++
 tests/qtest/ipmi-kcs-test.c |  83 +++++++++++++++++++++++++++
 2 files changed, 193 insertions(+)

diff --git a/hw/ipmi/ipmi_bmc_sim.c b/hw/ipmi/ipmi_bmc_sim.c
index 2ead46ee55..f4cea91fde 100644
--- a/hw/ipmi/ipmi_bmc_sim.c
+++ b/hw/ipmi/ipmi_bmc_sim.c
@@ -106,6 +106,7 @@
 
 #define IPMI_NETFN_TRANSPORT          0x0c
 
+#define IPMI_CMD_SET_LAN_CONFIG           0x01
 #define IPMI_CMD_GET_LAN_CONFIG           0x02
 
 
@@ -300,6 +301,7 @@ struct IPMIBmcSim {
     ((ibs)->lan.channel != 0 && (ibs)->lan.channel == (c))
 
 #define IPMI_BMC_LAN_CFG_CC_PARAM_NOT_SUPPORTED    0x80
+#define IPMI_BMC_LAN_CFG_CC_PARAM_READONLY         0x82
 
 #define IPMI_BMC_LAN_CFG_PARAM_SET_IN_PROGRESS        0x00
 #define IPMI_BMC_LAN_CFG_PARAM_AUTH_TYPE_SUPPORT      0x01
@@ -2131,6 +2133,113 @@ static inline bool is_valid_netmask(const uint8_t *netmask)
     return mask != 0 && (inverted & (inverted + 1)) == 0;
 }
 
+/*
+ * Request data (from cmd[2] on):
+ * bytes   meaning
+ *    1    [bits 3:0] channel number
+ *    2    parameter selector
+ * [3:N]   configuration parameter data (from cmd[4] on)
+ */
+static void set_lan_config(IPMIBmcSim *ibs,
+                           uint8_t *cmd, unsigned int cmd_len,
+                           RspBuffer *rsp)
+{
+    uint8_t channel;
+    uint8_t *param;  /* pointer to configuration parameter data */
+    unsigned int param_len;
+
+    if (ibs->lan.channel == 0) {
+        /* LAN channel disabled. Fail as if this command were not defined. */
+        rsp_buffer_set_error(rsp, IPMI_CC_INVALID_CMD);
+        return;
+    }
+    if (cmd_len < 5) {
+        rsp_buffer_set_error(rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID);
+        return;
+    }
+    channel = cmd[2] & 0xf;
+    param = cmd + 4;
+    param_len = cmd_len - 4;
+
+    if (!IPMI_BMC_CHANNEL_IS_LAN(ibs, channel)) {
+        rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
+        return;
+    }
+
+    switch (cmd[3]) {
+    case IPMI_BMC_LAN_CFG_PARAM_IP_ADDR:
+        if (param_len < NBYTES_IP) {
+            rsp_buffer_set_error(rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID);
+            return;
+        }
+        memcpy(ibs->lan.ipaddr, param, NBYTES_IP);
+        break;
+
+    case IPMI_BMC_LAN_CFG_PARAM_IP_ADDR_SOURCE:
+        if (param_len < 1) {
+            rsp_buffer_set_error(rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID);
+            return;
+        }
+        if (!IPMI_BMC_LAN_CFG_IS_VALID_IP_SOURCE(*param)) {
+            rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
+            return;
+        }
+        ibs->lan.ipsrc = *param;
+        break;
+
+    case IPMI_BMC_LAN_CFG_PARAM_MAC_ADDR:
+        if (param_len < NBYTES_MAC) {
+            rsp_buffer_set_error(rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID);
+            return;
+        }
+        memcpy(ibs->lan.macaddr.a, param, NBYTES_MAC);
+        break;
+
+    case IPMI_BMC_LAN_CFG_PARAM_SUBNET_MASK:
+        if (param_len < NBYTES_IP) {
+            rsp_buffer_set_error(rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID);
+            return;
+        }
+        if (!is_valid_netmask(param)) {
+            rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
+            return;
+        }
+        memcpy(ibs->lan.netmask, param, NBYTES_IP);
+        break;
+
+    case IPMI_BMC_LAN_CFG_PARAM_DEFAULT_GW_IP_ADDR:
+        if (param_len < NBYTES_IP) {
+            rsp_buffer_set_error(rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID);
+            return;
+        }
+        memcpy(ibs->lan.defgw_ipaddr, param, NBYTES_IP);
+        break;
+
+    case IPMI_BMC_LAN_CFG_PARAM_DEFAULT_GW_MAC_ADDR:
+        if (param_len < NBYTES_MAC) {
+            rsp_buffer_set_error(rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID);
+            return;
+        }
+        memcpy(ibs->lan.defgw_macaddr.a, param, NBYTES_MAC);
+        break;
+
+    case IPMI_BMC_LAN_CFG_PARAM_SET_IN_PROGRESS:
+    case IPMI_BMC_LAN_CFG_PARAM_AUTH_TYPE_SUPPORT:
+    case IPMI_BMC_LAN_CFG_PARAM_AUTH_TYPE_ENABLES:
+    case IPMI_BMC_LAN_CFG_PARAM_IPV4_HDR_PARAMS:
+    case IPMI_BMC_LAN_CFG_PARAM_BACKUP_GW_ADDR:
+    case IPMI_BMC_LAN_CFG_PARAM_BACKUP_GW_MAC_ADDR:
+    case IPMI_BMC_LAN_CFG_PARAM_COMMUNITY_STRING:
+    case IPMI_BMC_LAN_CFG_PARAM_NUM_DESTINATIONS:
+        rsp_buffer_set_error(rsp, IPMI_BMC_LAN_CFG_CC_PARAM_READONLY);
+        return;
+
+    default:
+        rsp_buffer_set_error(rsp, IPMI_BMC_LAN_CFG_CC_PARAM_NOT_SUPPORTED);
+        return;
+    }
+}
+
 /*
  * Request data (from cmd[2] to cmd[5] inclusive):
  * bytes   meaning
@@ -2329,6 +2438,7 @@ static const IPMINetfn storage_netfn = {
 };
 
 static const IPMICmdHandler transport_cmds[] = {
+    [IPMI_CMD_SET_LAN_CONFIG] = { set_lan_config },
     [IPMI_CMD_GET_LAN_CONFIG] = { get_lan_config },
 };
 static const IPMINetfn transport_netfn = {
diff --git a/tests/qtest/ipmi-kcs-test.c b/tests/qtest/ipmi-kcs-test.c
index d0a207477e..9bab0d84ad 100644
--- a/tests/qtest/ipmi-kcs-test.c
+++ b/tests/qtest/ipmi-kcs-test.c
@@ -318,6 +318,88 @@ static void test_kcs_lan_get(void)
 }
 
 
+/* set/get ip address: 192.0.2.2 */
+static uint8_t lan_set_ipaddr_cmd[] = { 0x30, 0x01, 0x01, 0x03,
+                                        0xc0, 0x00, 0x02, 0x02 };
+static uint8_t lan_set_ipaddr_rsp[] = { 0x34, 0x01, 0x00 };
+static uint8_t lan_get_ipaddr_cmd[] = { 0x30, 0x02, 0x01, 0x03, 0x00, 0x00 };
+static uint8_t lan_get_ipaddr_rsp[] = { 0x34, 0x02, 0x00, 0x11,
+                                        0xc0, 0x00, 0x02, 0x02 };
+/* set ip address source: static */
+static uint8_t lan_set_ipsrc_cmd[] = { 0x30, 0x01, 0x01, 0x04, 0x01 };
+static uint8_t lan_set_ipsrc_rsp[] = { 0x34, 0x01, 0x00 };
+
+/* set/get subnet mask: 255.255.255.0 */
+static uint8_t lan_set_netmask_cmd[] = { 0x30, 0x01, 0x01, 0x06,
+                                         0xff, 0xff, 0xff, 0x00 };
+static uint8_t lan_set_netmask_rsp[] = { 0x34, 0x01, 0x00 };
+static uint8_t lan_get_netmask_cmd[] = { 0x30, 0x02, 0x01, 0x06, 0x00, 0x00 };
+static uint8_t lan_get_netmask_rsp[] = { 0x34, 0x02, 0x00, 0x11,
+                                         0xff, 0xff, 0xff, 0x00 };
+
+/* set/get default gateway ip address: 192.0.2.1 */
+static uint8_t lan_set_defgw_ipaddr_cmd[] = { 0x30, 0x01, 0x01, 0x0c,
+                                              0xc0, 0x00, 0x02, 0x01 };
+static uint8_t lan_set_defgw_ipaddr_rsp[] = { 0x34, 0x01, 0x00 };
+static uint8_t lan_get_defgw_ipaddr_cmd[] = { 0x30, 0x02, 0x01, 0x0c,
+                                              0x00, 0x00 };
+static uint8_t lan_get_defgw_ipaddr_rsp[] = { 0x34, 0x02, 0x00, 0x11,
+                                              0xc0, 0x00, 0x02, 0x01 };
+
+/*
+ * Set and then get LAN configurations
+ */
+static void test_kcs_lan_set_get(void)
+{
+    uint8_t rsp[20];
+    unsigned int rsplen = 0;
+
+    /* set ip address */
+    rsplen = sizeof(rsp);
+    kcs_cmd(lan_set_ipaddr_cmd, sizeof(lan_set_ipaddr_cmd), rsp, &rsplen);
+    g_assert(rsplen == sizeof(lan_set_ipaddr_rsp));
+    g_assert(memcmp(lan_set_ipaddr_rsp, rsp, rsplen) == 0);
+
+    /* get ip address */
+    rsplen = sizeof(rsp);
+    kcs_cmd(lan_get_ipaddr_cmd, sizeof(lan_get_ipaddr_cmd), rsp, &rsplen);
+    g_assert(rsplen == sizeof(lan_get_ipaddr_rsp));
+    g_assert(memcmp(lan_get_ipaddr_rsp, rsp, rsplen) == 0);
+
+    /* set ip address source */
+    rsplen = sizeof(rsp);
+    kcs_cmd(lan_set_ipsrc_cmd, sizeof(lan_set_ipsrc_cmd), rsp, &rsplen);
+    g_assert(rsplen == sizeof(lan_set_ipsrc_rsp));
+    g_assert(memcmp(lan_set_ipsrc_rsp, rsp, rsplen) == 0);
+
+    /* set subnet mask */
+    rsplen = sizeof(rsp);
+    kcs_cmd(lan_set_netmask_cmd, sizeof(lan_set_netmask_cmd), rsp, &rsplen);
+    g_assert(rsplen == sizeof(lan_set_netmask_rsp));
+    g_assert(memcmp(lan_set_netmask_rsp, rsp, rsplen) == 0);
+
+    /* get subnet mask */
+    rsplen = sizeof(rsp);
+    kcs_cmd(lan_get_netmask_cmd, sizeof(lan_get_netmask_cmd), rsp, &rsplen);
+    g_assert(rsplen == sizeof(lan_get_netmask_rsp));
+    g_assert(memcmp(lan_get_netmask_rsp, rsp, rsplen) == 0);
+
+    /* set default gateway ip address */
+    rsplen = sizeof(rsp);
+    kcs_cmd(lan_set_defgw_ipaddr_cmd, sizeof(lan_set_defgw_ipaddr_cmd),
+            rsp, &rsplen);
+    g_assert(rsplen == sizeof(lan_set_defgw_ipaddr_rsp));
+    g_assert(memcmp(lan_set_defgw_ipaddr_rsp, rsp, rsplen) == 0);
+
+    /* get default gateway ip address */
+    rsplen = sizeof(rsp);
+    kcs_cmd(lan_get_defgw_ipaddr_cmd, sizeof(lan_get_defgw_ipaddr_cmd),
+            rsp, &rsplen);
+    g_assert(rsplen == sizeof(lan_get_defgw_ipaddr_rsp));
+    g_assert(memcmp(lan_get_defgw_ipaddr_rsp, rsp, rsplen) == 0);
+}
+
+
 int main(int argc, char **argv)
 {
     char *cmdline;
@@ -340,6 +422,7 @@ int main(int argc, char **argv)
     qtest_add_func("/ipmi/local/kcs_channel_access", test_kcs_channel_access);
     qtest_add_func("/ipmi/local/kcs_channel_info", test_kcs_channel_info);
     qtest_add_func("/ipmi/local/kcs_lan_get", test_kcs_lan_get);
+    qtest_add_func("/ipmi/local/kcs_lan_set_get", test_kcs_lan_set_get);
     ret = g_test_run();
     qtest_quit(global_qtest);
 
-- 
2.43.7



^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH 0/2] hw/ipmi/ipmi_bmc_sim: Get/set fake LAN config
  2025-10-28 18:01 [PATCH 0/2] hw/ipmi/ipmi_bmc_sim: Get/set fake LAN config Yunpeng Yang
  2025-10-28 18:01 ` [PATCH 1/2] hw/ipmi/ipmi_bmc_sim: Support getting fake LAN channel config Yunpeng Yang
  2025-10-28 18:01 ` [PATCH 2/2] hw/ipmi/ipmi_bmc_sim: Support setting " Yunpeng Yang
@ 2025-11-24 20:54 ` Corey Minyard
  2025-11-26 18:04   ` Yunpeng Yang
  2 siblings, 1 reply; 7+ messages in thread
From: Corey Minyard @ 2025-11-24 20:54 UTC (permalink / raw)
  To: Yunpeng Yang
  Cc: minyard@acm.org, farosas@suse.de, lvivier@redhat.com,
	pbonzini@redhat.com, qemu-devel@nongnu.org, Mark Cave-Ayland,
	Jonathan Davies, cornelia.huck@de.ibm.com

On Tue, Oct 28, 2025 at 06:01:18PM +0000, Yunpeng Yang wrote:
> Support for a fake LAN channel is added to the device `ipmi_bmc_sim`.
> Although there is no real LAN channel, some testing processes which
> require interactions with BMC LAN channel will become easier.
> 
> There's another device `ipmi_bmc_extern` which works together with some
> external BMC simulator, e.g., `ipmi_sim`. More comprehensive BMC
> simulation can be achieved with `ipmi_bmc_extern`. However,
> `ipmi_bmc_sim` is more light-weight and is built into QEMU.

I apologize for the time on this, it slipped between the cracks.

These both look good.  I can give a:

Reviewed-by: Corey Minyard <corey@minyard.net>

or 

Acked-by: Corey Minyard <corey@minyard.net>

or I can take it into my tree if you aren't bringing it in any place
else.

One thing you should try is doing a migration between a version 1 and
version 2 device, and between two version 2 devices, just to be sure
migration still works.  Assuming you haven't done this already.

-corey

> 
> Yunpeng Yang (2):
>   hw/ipmi/ipmi_bmc_sim: Support getting fake LAN channel config
>   hw/ipmi/ipmi_bmc_sim: Support setting fake LAN channel config
> 
>  hw/ipmi/ipmi_bmc_sim.c      | 407 +++++++++++++++++++++++++++++++++++-
>  include/hw/ipmi/ipmi.h      |   1 +
>  qemu-options.hx             |  26 +++
>  tests/qtest/ipmi-kcs-test.c | 143 +++++++++++++
>  4 files changed, 567 insertions(+), 10 deletions(-)
> 
> -- 
> 2.43.7
> 


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 0/2] hw/ipmi/ipmi_bmc_sim: Get/set fake LAN config
  2025-11-24 20:54 ` [PATCH 0/2] hw/ipmi/ipmi_bmc_sim: Get/set fake LAN config Corey Minyard
@ 2025-11-26 18:04   ` Yunpeng Yang
  2025-11-27 17:28     ` Yunpeng Yang
  0 siblings, 1 reply; 7+ messages in thread
From: Yunpeng Yang @ 2025-11-26 18:04 UTC (permalink / raw)
  To: corey@minyard.net
  Cc: minyard@acm.org, farosas@suse.de, lvivier@redhat.com,
	pbonzini@redhat.com, qemu-devel@nongnu.org, Mark Cave-Ayland,
	Jonathan Davies, cornelia.huck@de.ibm.com

[-- Attachment #1: Type: text/plain, Size: 2594 bytes --]

Hello Corey,

Thank you for your reply.

Please add tags or take the patches into your tree at your discretion.
I'm not bringing the patches in any place else.

I haven't tested migration between a version 1 and a version 2 device.
I'll do a test and tell you the result. Thank you for your suggestion.

Kind regards,
Yunpeng



________________________________
From: Corey Minyard <corey@minyard.net>
Sent: Monday, November 24, 2025 20:54
To: Yunpeng Yang <yunpeng.yang@nutanix.com>
Cc: minyard@acm.org <minyard@acm.org>; farosas@suse.de <farosas@suse.de>; lvivier@redhat.com <lvivier@redhat.com>; pbonzini@redhat.com <pbonzini@redhat.com>; qemu-devel@nongnu.org <qemu-devel@nongnu.org>; Mark Cave-Ayland <mark.caveayland@nutanix.com>; Jonathan Davies <jond@nutanix.com>; cornelia.huck@de.ibm.com <cornelia.huck@de.ibm.com>
Subject: Re: [PATCH 0/2] hw/ipmi/ipmi_bmc_sim: Get/set fake LAN config

!-------------------------------------------------------------------|
  CAUTION: External Email

|-------------------------------------------------------------------!

On Tue, Oct 28, 2025 at 06:01:18PM +0000, Yunpeng Yang wrote:
> Support for a fake LAN channel is added to the device `ipmi_bmc_sim`.
> Although there is no real LAN channel, some testing processes which
> require interactions with BMC LAN channel will become easier.
>
> There's another device `ipmi_bmc_extern` which works together with some
> external BMC simulator, e.g., `ipmi_sim`. More comprehensive BMC
> simulation can be achieved with `ipmi_bmc_extern`. However,
> `ipmi_bmc_sim` is more light-weight and is built into QEMU.

I apologize for the time on this, it slipped between the cracks.

These both look good.  I can give a:

Reviewed-by: Corey Minyard <corey@minyard.net>

or

Acked-by: Corey Minyard <corey@minyard.net>

or I can take it into my tree if you aren't bringing it in any place
else.

One thing you should try is doing a migration between a version 1 and
version 2 device, and between two version 2 devices, just to be sure
migration still works.  Assuming you haven't done this already.

-corey

>
> Yunpeng Yang (2):
>   hw/ipmi/ipmi_bmc_sim: Support getting fake LAN channel config
>   hw/ipmi/ipmi_bmc_sim: Support setting fake LAN channel config
>
>  hw/ipmi/ipmi_bmc_sim.c      | 407 +++++++++++++++++++++++++++++++++++-
>  include/hw/ipmi/ipmi.h      |   1 +
>  qemu-options.hx             |  26 +++
>  tests/qtest/ipmi-kcs-test.c | 143 +++++++++++++
>  4 files changed, 567 insertions(+), 10 deletions(-)
>
> --
> 2.43.7
>

[-- Attachment #2: Type: text/html, Size: 6133 bytes --]

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 0/2] hw/ipmi/ipmi_bmc_sim: Get/set fake LAN config
  2025-11-26 18:04   ` Yunpeng Yang
@ 2025-11-27 17:28     ` Yunpeng Yang
  0 siblings, 0 replies; 7+ messages in thread
From: Yunpeng Yang @ 2025-11-27 17:28 UTC (permalink / raw)
  To: corey@minyard.net
  Cc: minyard@acm.org, farosas@suse.de, lvivier@redhat.com,
	pbonzini@redhat.com, qemu-devel@nongnu.org, Mark Cave-Ayland,
	Jonathan Davies, cornelia.huck@de.ibm.com

[-- Attachment #1: Type: text/plain, Size: 3464 bytes --]

Hello Corey,

I have done a VM migration test from a v1 `ipmi_bmc_sim` qemu to a v2 `ipmi_bmc_sim` qemu. The migration was successful. The VM had `ipmi_bmc_sim` configured but with no LAN channel.
A v2 to v2 migration with LAN channel was also successful.

Kind regards,
Yunpeng

________________________________
From: Yunpeng Yang <yunpeng.yang@nutanix.com>
Sent: Wednesday, November 26, 2025 18:04
To: corey@minyard.net <corey@minyard.net>
Cc: minyard@acm.org <minyard@acm.org>; farosas@suse.de <farosas@suse.de>; lvivier@redhat.com <lvivier@redhat.com>; pbonzini@redhat.com <pbonzini@redhat.com>; qemu-devel@nongnu.org <qemu-devel@nongnu.org>; Mark Cave-Ayland <mark.caveayland@nutanix.com>; Jonathan Davies <jond@nutanix.com>; cornelia.huck@de.ibm.com <cornelia.huck@de.ibm.com>
Subject: Re: [PATCH 0/2] hw/ipmi/ipmi_bmc_sim: Get/set fake LAN config

Hello Corey,

Thank you for your reply.

Please add tags or take the patches into your tree at your discretion.
I'm not bringing the patches in any place else.

I haven't tested migration between a version 1 and a version 2 device.
I'll do a test and tell you the result. Thank you for your suggestion.

Kind regards,
Yunpeng



________________________________
From: Corey Minyard <corey@minyard.net>
Sent: Monday, November 24, 2025 20:54
To: Yunpeng Yang <yunpeng.yang@nutanix.com>
Cc: minyard@acm.org <minyard@acm.org>; farosas@suse.de <farosas@suse.de>; lvivier@redhat.com <lvivier@redhat.com>; pbonzini@redhat.com <pbonzini@redhat.com>; qemu-devel@nongnu.org <qemu-devel@nongnu.org>; Mark Cave-Ayland <mark.caveayland@nutanix.com>; Jonathan Davies <jond@nutanix.com>; cornelia.huck@de.ibm.com <cornelia.huck@de.ibm.com>
Subject: Re: [PATCH 0/2] hw/ipmi/ipmi_bmc_sim: Get/set fake LAN config

!-------------------------------------------------------------------|
  CAUTION: External Email

|-------------------------------------------------------------------!

On Tue, Oct 28, 2025 at 06:01:18PM +0000, Yunpeng Yang wrote:
> Support for a fake LAN channel is added to the device `ipmi_bmc_sim`.
> Although there is no real LAN channel, some testing processes which
> require interactions with BMC LAN channel will become easier.
>
> There's another device `ipmi_bmc_extern` which works together with some
> external BMC simulator, e.g., `ipmi_sim`. More comprehensive BMC
> simulation can be achieved with `ipmi_bmc_extern`. However,
> `ipmi_bmc_sim` is more light-weight and is built into QEMU.

I apologize for the time on this, it slipped between the cracks.

These both look good.  I can give a:

Reviewed-by: Corey Minyard <corey@minyard.net>

or

Acked-by: Corey Minyard <corey@minyard.net>

or I can take it into my tree if you aren't bringing it in any place
else.

One thing you should try is doing a migration between a version 1 and
version 2 device, and between two version 2 devices, just to be sure
migration still works.  Assuming you haven't done this already.

-corey

>
> Yunpeng Yang (2):
>   hw/ipmi/ipmi_bmc_sim: Support getting fake LAN channel config
>   hw/ipmi/ipmi_bmc_sim: Support setting fake LAN channel config
>
>  hw/ipmi/ipmi_bmc_sim.c      | 407 +++++++++++++++++++++++++++++++++++-
>  include/hw/ipmi/ipmi.h      |   1 +
>  qemu-options.hx             |  26 +++
>  tests/qtest/ipmi-kcs-test.c | 143 +++++++++++++
>  4 files changed, 567 insertions(+), 10 deletions(-)
>
> --
> 2.43.7
>

[-- Attachment #2: Type: text/html, Size: 8745 bytes --]

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 1/2] hw/ipmi/ipmi_bmc_sim: Support getting fake LAN channel config
  2025-10-28 18:01 ` [PATCH 1/2] hw/ipmi/ipmi_bmc_sim: Support getting fake LAN channel config Yunpeng Yang
@ 2025-12-01 20:18   ` Philippe Mathieu-Daudé
  0 siblings, 0 replies; 7+ messages in thread
From: Philippe Mathieu-Daudé @ 2025-12-01 20:18 UTC (permalink / raw)
  To: Yunpeng Yang, minyard@acm.org
  Cc: farosas@suse.de, lvivier@redhat.com, pbonzini@redhat.com,
	qemu-devel@nongnu.org, Mark Cave-Ayland, corey@minyard.net,
	Jonathan Davies, cornelia.huck@de.ibm.com

Hi Yunpeng,

On 28/10/25 19:01, Yunpeng Yang wrote:
> The following IPMI commands are added or modified to support getting
> fake LAN channel configurations from the `ipmi_bmc_sim` device:
> * Get Channel Access;
> * Get Channel Info Command;
> * Get LAN Configuration Parameters.
> 
> The fake LAN channel configurations can be specified from QEMU
> commandline options for device `ipmi_bmc_sim`. Inside the guest OS, the
> configurations can be retrieved from the device using some IPMI tools,
> e.g., `ipmitool lan print`.
> Note, there is not a real LAN channel. The fake LAN channel is suitable
> for testing purposes.
> 
> Signed-off-by: Yunpeng Yang <yunpeng.yang@nutanix.com>
> ---
>   hw/ipmi/ipmi_bmc_sim.c      | 297 ++++++++++++++++++++++++++++++++++--
>   include/hw/ipmi/ipmi.h      |   1 +
>   qemu-options.hx             |  26 ++++
>   tests/qtest/ipmi-kcs-test.c |  60 ++++++++
>   4 files changed, 374 insertions(+), 10 deletions(-)


>   /* Same as a timespec struct. */
>   struct ipmi_time {
> @@ -170,6 +177,23 @@ typedef struct IPMISensor {
>   #define MAX_SENSORS 20
>   #define IPMI_WATCHDOG_SENSOR 0
>   
> +#define NBYTES_IP  4
> +#define NBYTES_MAC 6
> +
> +typedef struct IPMILan {
> +    uint8_t channel;
> +    uint8_t ipaddr[NBYTES_IP];
> +    uint8_t ipsrc;
> +    MACAddr macaddr;
> +    uint8_t netmask[NBYTES_IP];
> +    uint8_t defgw_ipaddr[NBYTES_IP];
> +    MACAddr defgw_macaddr;
> +
> +    char *arg_ipaddr;
> +    char *arg_netmask;
> +    char *arg_defgw_ipaddr;
> +} IPMILan;
> +
>   #define MAX_NETFNS 64
>   
>   typedef struct IPMIRcvBufEntry {
> @@ -215,6 +239,7 @@ struct IPMIBmcSim {
>       IPMIFru fru;
>       IPMISensor sensors[MAX_SENSORS];
>       char *sdr_filename;
> +    IPMILan lan;
>   

[...]

> +static inline bool is_valid_netmask(const uint8_t *netmask)
> +{
> +    uint32_t mask = netmask[3];
> +    uint32_t inverted;
> +
> +    mask |= (uint32_t) netmask[2] << 8;
> +    mask |= (uint32_t) netmask[1] << 16;
> +    mask |= (uint32_t) netmask[0] << 24;

Why manually byteswap?

I'd expect such helper already available in include/net/ somewhere,
otherwise what about:

   static bool is_ipv4_netmask_valid(const void *buf)
   {
       uint32_t netmask = ldl_be_p(buf);

       return clo32(netmask) + ctz32(netmask) == 32;
   }

> +    inverted = ~mask;
> +    return mask != 0 && (inverted & (inverted + 1)) == 0;
> +}


> @@ -2176,7 +2395,7 @@ static void ipmi_sdr_init(IPMIBmcSim *ibs)
>   
>   static const VMStateDescription vmstate_ipmi_sim = {
>       .name = TYPE_IPMI_BMC_SIMULATOR,
> -    .version_id = 1,
> +    .version_id = 2,
>       .minimum_version_id = 1,
>       .fields = (const VMStateField[]) {
>           VMSTATE_UINT8(bmc_global_enables, IPMIBmcSim),
> @@ -2198,6 +2417,13 @@ static const VMStateDescription vmstate_ipmi_sim = {
>           VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].deassert_states,
>                          IPMIBmcSim),
>           VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].assert_enable, IPMIBmcSim),
> +        VMSTATE_UINT8_V(lan.channel, IPMIBmcSim, 2),
> +        VMSTATE_UINT8_ARRAY_V(lan.ipaddr, IPMIBmcSim, NBYTES_IP, 2),
> +        VMSTATE_UINT8_V(lan.ipsrc, IPMIBmcSim, 2),
> +        VMSTATE_UINT8_ARRAY_V(lan.macaddr.a, IPMIBmcSim, NBYTES_MAC, 2),
> +        VMSTATE_UINT8_ARRAY_V(lan.netmask, IPMIBmcSim, NBYTES_IP, 2),
> +        VMSTATE_UINT8_ARRAY_V(lan.defgw_ipaddr, IPMIBmcSim, NBYTES_IP, 2),
> +        VMSTATE_UINT8_ARRAY_V(lan.defgw_macaddr.a, IPMIBmcSim, NBYTES_MAC, 2),

Safer would be to add a VMStateDescription for the new IPMILan
structure and link it as subsections, so other code using could just
link as subsection, not duplicating the VMSTATE_FOO() macros.

>           VMSTATE_END_OF_LIST()
>       }
>   };

Regards,

Phil.


^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2025-12-01 20:18 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-10-28 18:01 [PATCH 0/2] hw/ipmi/ipmi_bmc_sim: Get/set fake LAN config Yunpeng Yang
2025-10-28 18:01 ` [PATCH 1/2] hw/ipmi/ipmi_bmc_sim: Support getting fake LAN channel config Yunpeng Yang
2025-12-01 20:18   ` Philippe Mathieu-Daudé
2025-10-28 18:01 ` [PATCH 2/2] hw/ipmi/ipmi_bmc_sim: Support setting " Yunpeng Yang
2025-11-24 20:54 ` [PATCH 0/2] hw/ipmi/ipmi_bmc_sim: Get/set fake LAN config Corey Minyard
2025-11-26 18:04   ` Yunpeng Yang
2025-11-27 17:28     ` Yunpeng Yang

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).