[PATCH v1 3/8] conf, qemu: adding VIR_DOMAIN_DEVICE_TPMPROXY device

Daniel Henrique Barboza danielhb413 at gmail.com
Fri May 8 12:06:52 UTC 2020


This new device will be used to represent a single instance of a
TPM Proxy for the domain.

XML functions to parse and format the device from the XML definition
will be added in the next patch.

Signed-off-by: Daniel Henrique Barboza <danielhb413 at gmail.com>
---
 src/conf/domain_capabilities.c |  1 +
 src/conf/domain_conf.c         | 68 ++++++++++++++++++++++++++++++++++
 src/conf/domain_conf.h         | 18 +++++++++
 src/conf/virconftypes.h        |  3 ++
 src/qemu/qemu_command.c        |  1 +
 src/qemu/qemu_domain.c         | 14 +++++++
 src/qemu/qemu_domain_address.c |  2 +
 src/qemu/qemu_driver.c         |  5 +++
 src/qemu/qemu_hotplug.c        |  3 ++
 src/qemu/qemu_validate.c       | 37 ++++++++++++++++++
 10 files changed, 152 insertions(+)

diff --git a/src/conf/domain_capabilities.c b/src/conf/domain_capabilities.c
index 921d795630..485fa9a22d 100644
--- a/src/conf/domain_capabilities.c
+++ b/src/conf/domain_capabilities.c
@@ -703,6 +703,7 @@ virDomainCapsDeviceDefValidate(const virDomainCaps *caps,
     case VIR_DOMAIN_DEVICE_TPM:
     case VIR_DOMAIN_DEVICE_PANIC:
     case VIR_DOMAIN_DEVICE_IOMMU:
+    case VIR_DOMAIN_DEVICE_TPMPROXY:
     case VIR_DOMAIN_DEVICE_NONE:
     case VIR_DOMAIN_DEVICE_LAST:
         break;
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 83748354b0..4c731b9f36 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -323,6 +323,7 @@ VIR_ENUM_IMPL(virDomainDevice,
               "memory",
               "iommu",
               "vsock",
+              "tpmproxy",
 );
 
 VIR_ENUM_IMPL(virDomainDiskDevice,
@@ -1180,6 +1181,12 @@ VIR_ENUM_IMPL(virDomainTPMVersion,
               "2.0",
 );
 
+VIR_ENUM_IMPL(virDomainTPMProxyModel,
+              VIR_DOMAIN_TPMPROXY_MODEL_LAST,
+              "default",
+              "spapr-tpm-proxy",
+);
+
 VIR_ENUM_IMPL(virDomainIOMMUModel,
               VIR_DOMAIN_IOMMU_MODEL_LAST,
               "intel",
@@ -3061,6 +3068,17 @@ void virDomainTPMDefFree(virDomainTPMDefPtr def)
     VIR_FREE(def);
 }
 
+void virDomainTPMProxyDefFree(virDomainTPMProxyDefPtr def)
+{
+    if (!def)
+        return;
+
+    VIR_FREE(def->path);
+    virDomainDeviceInfoClear(&def->info);
+    VIR_FREE(def);
+
+}
+
 void virDomainHostdevDefFree(virDomainHostdevDefPtr def)
 {
     if (!def)
@@ -3187,6 +3205,9 @@ void virDomainDeviceDefFree(virDomainDeviceDefPtr def)
     case VIR_DOMAIN_DEVICE_TPM:
         virDomainTPMDefFree(def->data.tpm);
         break;
+    case VIR_DOMAIN_DEVICE_TPMPROXY:
+        virDomainTPMProxyDefFree(def->data.tpmproxy);
+        break;
     case VIR_DOMAIN_DEVICE_PANIC:
         virDomainPanicDefFree(def->data.panic);
         break;
@@ -3480,6 +3501,7 @@ void virDomainDefFree(virDomainDefPtr def)
     VIR_FREE(def->mems);
 
     virDomainTPMDefFree(def->tpm);
+    virDomainTPMProxyDefFree(def->tpmproxy);
 
     for (i = 0; i < def->npanics; i++)
         virDomainPanicDefFree(def->panics[i]);
@@ -4038,6 +4060,8 @@ virDomainDeviceGetInfo(virDomainDeviceDefPtr device)
         return &device->data.memory->info;
     case VIR_DOMAIN_DEVICE_VSOCK:
         return &device->data.vsock->info;
+    case VIR_DOMAIN_DEVICE_TPMPROXY:
+        return &device->data.tpmproxy->info;
 
     /* The following devices do not contain virDomainDeviceInfo */
     case VIR_DOMAIN_DEVICE_LEASE:
@@ -4137,6 +4161,9 @@ virDomainDeviceSetData(virDomainDeviceDefPtr device,
     case VIR_DOMAIN_DEVICE_LEASE:
         device->data.lease = devicedata;
         break;
+    case VIR_DOMAIN_DEVICE_TPMPROXY:
+        device->data.tpmproxy = devicedata;
+        break;
     case VIR_DOMAIN_DEVICE_NONE:
     case VIR_DOMAIN_DEVICE_LAST:
         break;
@@ -4318,6 +4345,12 @@ virDomainDeviceInfoIterateInternal(virDomainDefPtr def,
         if ((rc = cb(def, &device, &def->tpm->info, opaque)) != 0)
             return rc;
     }
+    if (def->tpmproxy) {
+        device.type = VIR_DOMAIN_DEVICE_TPMPROXY;
+        device.data.tpmproxy = def->tpmproxy;
+        if ((rc = cb(def, &device, &def->tpmproxy->info, opaque)) != 0)
+            return rc;
+    }
     device.type = VIR_DOMAIN_DEVICE_PANIC;
     for (i = 0; i < def->npanics; i++) {
         device.data.panic = def->panics[i];
@@ -4403,6 +4436,7 @@ virDomainDeviceInfoIterateInternal(virDomainDefPtr def,
     case VIR_DOMAIN_DEVICE_MEMORY:
     case VIR_DOMAIN_DEVICE_IOMMU:
     case VIR_DOMAIN_DEVICE_VSOCK:
+    case VIR_DOMAIN_DEVICE_TPMPROXY:
         break;
     }
 #endif
@@ -5395,6 +5429,7 @@ virDomainDeviceDefPostParseCommon(virDomainDeviceDefPtr dev,
     case VIR_DOMAIN_DEVICE_PANIC:
     case VIR_DOMAIN_DEVICE_MEMORY:
     case VIR_DOMAIN_DEVICE_IOMMU:
+    case VIR_DOMAIN_DEVICE_TPMPROXY:
         ret = 0;
         break;
 
@@ -6795,6 +6830,7 @@ virDomainDeviceDefValidateInternal(const virDomainDeviceDef *dev,
     case VIR_DOMAIN_DEVICE_TPM:
     case VIR_DOMAIN_DEVICE_PANIC:
     case VIR_DOMAIN_DEVICE_IOMMU:
+    case VIR_DOMAIN_DEVICE_TPMPROXY:
     case VIR_DOMAIN_DEVICE_NONE:
     case VIR_DOMAIN_DEVICE_LAST:
         break;
@@ -17039,6 +17075,7 @@ virDomainDeviceDefParse(const char *xmlStr,
                                                           flags)))
             return NULL;
         break;
+    case VIR_DOMAIN_DEVICE_TPMPROXY:
     case VIR_DOMAIN_DEVICE_NONE:
     case VIR_DOMAIN_DEVICE_LAST:
         break;
@@ -23743,6 +23780,25 @@ virDomainTPMDefCheckABIStability(virDomainTPMDefPtr src,
 }
 
 
+static bool
+virDomainTPMProxyDefCheckABIStability(virDomainTPMProxyDefPtr src,
+                                      virDomainTPMProxyDefPtr dst)
+{
+    if (src->model != dst->model) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("Target TPM Proxy device model doesn't match source"));
+        return false;
+    }
+
+    if (STRNEQ_NULLABLE(src->path, dst->path)) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("Target TPM Proxy device path doesn't match source"));
+        return false;
+    }
+
+    return virDomainDeviceInfoCheckABIStability(&src->info, &dst->info);
+}
+
 static bool
 virDomainMemtuneCheckABIStability(const virDomainDef *src,
                                   const virDomainDef *dst,
@@ -24355,6 +24411,16 @@ virDomainDefCheckABIStabilityFlags(virDomainDefPtr src,
         goto error;
     }
 
+    if (src->tpmproxy && dst->tpmproxy) {
+        if (!virDomainTPMProxyDefCheckABIStability(src->tpmproxy, dst->tpmproxy))
+            goto error;
+    } else if (src->tpmproxy || dst->tpmproxy) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("Either both target and source domains or none of "
+                         "them must have TPM Proxy device present"));
+        goto error;
+    }
+
     if (src->nmems != dst->nmems) {
         virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                        _("Target domain memory device count %zu "
@@ -24427,6 +24493,7 @@ virDomainDefCheckABIStabilityFlags(virDomainDefPtr src,
     case VIR_DOMAIN_DEVICE_MEMORY:
     case VIR_DOMAIN_DEVICE_IOMMU:
     case VIR_DOMAIN_DEVICE_VSOCK:
+    case VIR_DOMAIN_DEVICE_TPMPROXY:
         break;
     }
 #endif
@@ -30977,6 +31044,7 @@ virDomainDeviceDefCopy(virDomainDeviceDefPtr src,
     case VIR_DOMAIN_DEVICE_MEMBALLOON:
     case VIR_DOMAIN_DEVICE_NVRAM:
     case VIR_DOMAIN_DEVICE_IOMMU:
+    case VIR_DOMAIN_DEVICE_TPMPROXY:
     case VIR_DOMAIN_DEVICE_LAST:
         virReportError(VIR_ERR_INTERNAL_ERROR,
                        _("Copying definition of '%d' type "
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 4afd8f04bc..d9b6bc5a22 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -85,6 +85,7 @@ typedef enum {
     VIR_DOMAIN_DEVICE_MEMORY,
     VIR_DOMAIN_DEVICE_IOMMU,
     VIR_DOMAIN_DEVICE_VSOCK,
+    VIR_DOMAIN_DEVICE_TPMPROXY,
 
     VIR_DOMAIN_DEVICE_LAST
 } virDomainDeviceType;
@@ -116,6 +117,7 @@ struct _virDomainDeviceDef {
         virDomainMemoryDefPtr memory;
         virDomainIOMMUDefPtr iommu;
         virDomainVsockDefPtr vsock;
+        virDomainTPMProxyDefPtr tpmproxy;
     } data;
 };
 
@@ -1330,6 +1332,19 @@ struct _virDomainTPMDef {
     } data;
 };
 
+typedef enum {
+    VIR_DOMAIN_TPMPROXY_MODEL_DEFAULT,
+    VIR_DOMAIN_TPMPROXY_MODEL_SPAPR,
+
+    VIR_DOMAIN_TPMPROXY_MODEL_LAST
+} virDomainTPMProxyModel;
+
+struct _virDomainTPMProxyDef {
+    virDomainDeviceInfo info;
+    int model; /* virDomainTPMProxyModel */
+    char *path;
+};
+
 typedef enum {
     VIR_DOMAIN_INPUT_TYPE_MOUSE,
     VIR_DOMAIN_INPUT_TYPE_TABLET,
@@ -2625,6 +2640,7 @@ struct _virDomainDef {
     virDomainMemballoonDefPtr memballoon;
     virDomainNVRAMDefPtr nvram;
     virDomainTPMDefPtr tpm;
+    virDomainTPMProxyDefPtr tpmproxy;
     virCPUDefPtr cpu;
     virSysinfoDefPtr sysinfo;
     virDomainRedirFilterDefPtr redirfilter;
@@ -3023,6 +3039,7 @@ virDomainDeviceInfoPtr virDomainDeviceGetInfo(virDomainDeviceDefPtr device);
 void virDomainDeviceSetData(virDomainDeviceDefPtr device,
                             void *devicedata);
 void virDomainTPMDefFree(virDomainTPMDefPtr def);
+void virDomainTPMProxyDefFree(virDomainTPMProxyDefPtr def);
 
 typedef int (*virDomainDeviceInfoCallback)(virDomainDefPtr def,
                                            virDomainDeviceDefPtr dev,
@@ -3594,6 +3611,7 @@ VIR_ENUM_DECL(virDomainRNGBackend);
 VIR_ENUM_DECL(virDomainTPMModel);
 VIR_ENUM_DECL(virDomainTPMBackend);
 VIR_ENUM_DECL(virDomainTPMVersion);
+VIR_ENUM_DECL(virDomainTPMProxyModel);
 VIR_ENUM_DECL(virDomainMemoryModel);
 VIR_ENUM_DECL(virDomainMemoryBackingModel);
 VIR_ENUM_DECL(virDomainMemorySource);
diff --git a/src/conf/virconftypes.h b/src/conf/virconftypes.h
index 1c62cde251..5c4a149f24 100644
--- a/src/conf/virconftypes.h
+++ b/src/conf/virconftypes.h
@@ -312,6 +312,9 @@ typedef virDomainSoundDef *virDomainSoundDefPtr;
 typedef struct _virDomainTPMDef virDomainTPMDef;
 typedef virDomainTPMDef *virDomainTPMDefPtr;
 
+typedef struct _virDomainTPMProxyDef virDomainTPMProxyDef;
+typedef virDomainTPMProxyDef *virDomainTPMProxyDefPtr;
+
 typedef struct _virDomainThreadSchedParam virDomainThreadSchedParam;
 typedef virDomainThreadSchedParam *virDomainThreadSchedParamPtr;
 
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 269bdbaf56..9065164b1d 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -537,6 +537,7 @@ qemuBuildVirtioDevStr(virBufferPtr buf,
         case VIR_DOMAIN_DEVICE_PANIC:
         case VIR_DOMAIN_DEVICE_MEMORY:
         case VIR_DOMAIN_DEVICE_IOMMU:
+        case VIR_DOMAIN_DEVICE_TPMPROXY:
         case VIR_DOMAIN_DEVICE_LAST:
         default:
             return 0;
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
index 9c629c31a3..3e86797093 100644
--- a/src/qemu/qemu_domain.c
+++ b/src/qemu/qemu_domain.c
@@ -5923,6 +5923,16 @@ qemuDomainTPMDefPostParse(virDomainTPMDefPtr tpm,
 }
 
 
+static int
+qemuDomainTPMProxyDefPostParse(virDomainTPMProxyDefPtr tpmproxy)
+{
+    if (tpmproxy->model == VIR_DOMAIN_TPMPROXY_MODEL_DEFAULT)
+        tpmproxy->model = VIR_DOMAIN_TPMPROXY_MODEL_SPAPR;
+
+    return 0;
+}
+
+
 static int
 qemuDomainDeviceDefPostParse(virDomainDeviceDefPtr dev,
                              const virDomainDef *def,
@@ -5980,6 +5990,10 @@ qemuDomainDeviceDefPostParse(virDomainDeviceDefPtr dev,
         ret = qemuDomainTPMDefPostParse(dev->data.tpm, def->os.arch);
         break;
 
+    case VIR_DOMAIN_DEVICE_TPMPROXY:
+        ret = qemuDomainTPMProxyDefPostParse(dev->data.tpmproxy);
+        break;
+
     case VIR_DOMAIN_DEVICE_LEASE:
     case VIR_DOMAIN_DEVICE_FS:
     case VIR_DOMAIN_DEVICE_INPUT:
diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c
index 07431343ed..566516f8b5 100644
--- a/src/qemu/qemu_domain_address.c
+++ b/src/qemu/qemu_domain_address.c
@@ -528,6 +528,7 @@ qemuDomainDeviceSupportZPCI(virDomainDeviceDefPtr device)
     case VIR_DOMAIN_DEVICE_MEMORY:
     case VIR_DOMAIN_DEVICE_IOMMU:
     case VIR_DOMAIN_DEVICE_VSOCK:
+    case VIR_DOMAIN_DEVICE_TPMPROXY:
         break;
 
     case VIR_DOMAIN_DEVICE_NONE:
@@ -1031,6 +1032,7 @@ qemuDomainDeviceCalculatePCIConnectFlags(virDomainDeviceDefPtr dev,
     case VIR_DOMAIN_DEVICE_HUB:
     case VIR_DOMAIN_DEVICE_REDIRDEV:
     case VIR_DOMAIN_DEVICE_SMARTCARD:
+    case VIR_DOMAIN_DEVICE_TPMPROXY:
         /* These devices don't even have a DeviceInfo */
     case VIR_DOMAIN_DEVICE_LEASE:
     case VIR_DOMAIN_DEVICE_GRAPHICS:
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 1c7c87128d..57575b705f 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -7956,6 +7956,7 @@ qemuDomainAttachDeviceLive(virDomainObjPtr vm,
     case VIR_DOMAIN_DEVICE_TPM:
     case VIR_DOMAIN_DEVICE_PANIC:
     case VIR_DOMAIN_DEVICE_IOMMU:
+    case VIR_DOMAIN_DEVICE_TPMPROXY:
     case VIR_DOMAIN_DEVICE_LAST:
         virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                        _("live attach of device '%s' is not supported"),
@@ -8090,6 +8091,7 @@ qemuDomainUpdateDeviceLive(virDomainObjPtr vm,
     case VIR_DOMAIN_DEVICE_PANIC:
     case VIR_DOMAIN_DEVICE_IOMMU:
     case VIR_DOMAIN_DEVICE_VSOCK:
+    case VIR_DOMAIN_DEVICE_TPMPROXY:
     case VIR_DOMAIN_DEVICE_LAST:
         virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                        _("live update of device '%s' is not supported"),
@@ -8311,6 +8313,7 @@ qemuDomainAttachDeviceConfig(virDomainDefPtr vmdef,
     case VIR_DOMAIN_DEVICE_TPM:
     case VIR_DOMAIN_DEVICE_PANIC:
     case VIR_DOMAIN_DEVICE_IOMMU:
+    case VIR_DOMAIN_DEVICE_TPMPROXY:
     case VIR_DOMAIN_DEVICE_LAST:
          virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                         _("persistent attach of device '%s' is not supported"),
@@ -8513,6 +8516,7 @@ qemuDomainDetachDeviceConfig(virDomainDefPtr vmdef,
     case VIR_DOMAIN_DEVICE_TPM:
     case VIR_DOMAIN_DEVICE_PANIC:
     case VIR_DOMAIN_DEVICE_IOMMU:
+    case VIR_DOMAIN_DEVICE_TPMPROXY:
     case VIR_DOMAIN_DEVICE_LAST:
         virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                        _("persistent detach of device '%s' is not supported"),
@@ -8620,6 +8624,7 @@ qemuDomainUpdateDeviceConfig(virDomainDefPtr vmdef,
     case VIR_DOMAIN_DEVICE_PANIC:
     case VIR_DOMAIN_DEVICE_IOMMU:
     case VIR_DOMAIN_DEVICE_VSOCK:
+    case VIR_DOMAIN_DEVICE_TPMPROXY:
     case VIR_DOMAIN_DEVICE_LAST:
         virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                        _("persistent update of device '%s' is not supported"),
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index 60d0729f1e..aba80c87d3 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -4980,6 +4980,7 @@ qemuDomainRemoveAuditDevice(virDomainObjPtr vm,
     case VIR_DOMAIN_DEVICE_TPM:
     case VIR_DOMAIN_DEVICE_PANIC:
     case VIR_DOMAIN_DEVICE_IOMMU:
+    case VIR_DOMAIN_DEVICE_TPMPROXY:
     case VIR_DOMAIN_DEVICE_LAST:
         /* libvirt doesn't yet support detaching these devices */
         break;
@@ -5078,6 +5079,7 @@ qemuDomainRemoveDevice(virQEMUDriverPtr driver,
     case VIR_DOMAIN_DEVICE_TPM:
     case VIR_DOMAIN_DEVICE_PANIC:
     case VIR_DOMAIN_DEVICE_IOMMU:
+    case VIR_DOMAIN_DEVICE_TPMPROXY:
     case VIR_DOMAIN_DEVICE_LAST:
         virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                        _("don't know how to remove a %s device"),
@@ -5849,6 +5851,7 @@ qemuDomainDetachDeviceLive(virDomainObjPtr vm,
     case VIR_DOMAIN_DEVICE_TPM:
     case VIR_DOMAIN_DEVICE_PANIC:
     case VIR_DOMAIN_DEVICE_IOMMU:
+    case VIR_DOMAIN_DEVICE_TPMPROXY:
     case VIR_DOMAIN_DEVICE_LAST:
         virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                        _("live detach of device '%s' is not supported"),
diff --git a/src/qemu/qemu_validate.c b/src/qemu/qemu_validate.c
index 9debac6b30..733850416a 100644
--- a/src/qemu/qemu_validate.c
+++ b/src/qemu/qemu_validate.c
@@ -3326,6 +3326,38 @@ qemuValidateDomainDeviceDefTPM(virDomainTPMDef *tpm,
 }
 
 
+static int
+qemuValidateDomainDeviceDefTPMProxy(virDomainTPMProxyDef *tpmproxy,
+                                    const virDomainDef *def,
+                                    virQEMUCapsPtr qemuCaps)
+{
+    if (!ARCH_IS_PPC64(def->os.arch)) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("TPM Proxy device is only supported "
+                         "for PPC64 guests"));
+        return -1;
+    }
+
+    switch ((virDomainTPMProxyModel)tpmproxy->model) {
+    case VIR_DOMAIN_TPMPROXY_MODEL_DEFAULT:
+    case VIR_DOMAIN_TPMPROXY_MODEL_SPAPR:
+        if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_SPAPR_TPM_PROXY)) {
+            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                           _("TPM Proxy is not supported "
+                             "with this QEMU binary"));
+            return -1;
+        }
+        break;
+    case VIR_DOMAIN_TPMPROXY_MODEL_LAST:
+    default:
+        virReportEnumRangeError(virDomainTPMProxyModel,
+                                tpmproxy->model);
+        return -1;
+    }
+
+    return 0;
+}
+
 static int
 qemuValidateDomainDeviceDefInput(const virDomainInputDef *input,
                                  const virDomainDef *def,
@@ -3722,6 +3754,11 @@ qemuValidateDomainDeviceDef(const virDomainDeviceDef *dev,
         ret = qemuValidateDomainDeviceDefMemory(dev->data.memory, qemuCaps);
         break;
 
+    case VIR_DOMAIN_DEVICE_TPMPROXY:
+        ret = qemuValidateDomainDeviceDefTPMProxy(dev->data.tpmproxy,
+                                                  def, qemuCaps);
+        break;
+
     case VIR_DOMAIN_DEVICE_LEASE:
     case VIR_DOMAIN_DEVICE_SHMEM:
     case VIR_DOMAIN_DEVICE_PANIC:
-- 
2.26.2





More information about the libvir-list mailing list