[PATCH 0/8] Support for full function consoles

Motivation: the current libvirt-cim support for consoles is very limited in that it doesn't allow to specify the target and source types supported by libvirt. Having full support of the libvirt console feature is however mandatory for architectures like s390. The current implementation using a Graphics_RASD to represent consoles cannot easily be extended without breaking the existing implementation (or without being entirely unusable). Therefore a new RASD class is added to represent consoles in the model. Since there's no SVPC resource type for a console we use the combination of ResourceType = 1 (Other) and OtherResourceType = "console" for the new RASD instances. In order to be backward compatible, the only console type supported by older libvirt-cim versions (target type 'pty') will still be returned as Graphics_RASD. In the long run, this should be deprecated. Thilo Boehm (6): schema: Add CIM_ResourceAllocationSettingData for console resources schema: New SVPC types for chardev/consoles libxkutil: Console Support RASD: Provider Support for Console RASDs VSMS: Support for domains with console devices VSMS: add default console Viktor Mihajlovski (2): VSMS: Set resource types for default devices Device: CIM_LogicalDevice for consoles libxkutil/device_parsing.c | 316 ++++++++++++++++++- libxkutil/device_parsing.h | 43 ++- libxkutil/xmlgen.c | 191 +++++++++++- schema/ResourceAllocationSettingData.mof | 247 ++++++++++++++- schema/ResourceAllocationSettingData.registration | 5 +- src/Virt_Device.c | 33 ++ src/Virt_RASD.c | 148 ++++++++- src/Virt_VirtualSystemManagementService.c | 336 +++++++++++++++++++-- src/svpc_types.h | 102 ++++++- 9 files changed, 1384 insertions(+), 37 deletions(-) -- 1.7.9.5

The default graphics and input devices were built without their resource types being set correctly. This has not hurted yet. Future changes will however require that the device resource type is matching the actual device type. Signed-off-by: Viktor Mihajlovski <mihajlov@linux.vnet.ibm.com> Reviewed-by: Boris Fiuczynski <fiuczy@linux.vnet.ibm.com> --- src/Virt_VirtualSystemManagementService.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Virt_VirtualSystemManagementService.c b/src/Virt_VirtualSystemManagementService.c index 79dec73..6629b35 100644 --- a/src/Virt_VirtualSystemManagementService.c +++ b/src/Virt_VirtualSystemManagementService.c @@ -581,6 +581,7 @@ static bool default_graphics_device(struct domain *domain) return false; } + domain->dev_graphics->type = CIM_RES_TYPE_GRAPHICS; domain->dev_graphics->dev.graphics.type = strdup("vnc"); domain->dev_graphics->dev.graphics.dev.vnc.port = strdup("-1"); domain->dev_graphics->dev.graphics.dev.vnc.host = strdup("127.0.0.1"); @@ -609,6 +610,7 @@ static bool default_input_device(struct domain *domain) return false; } + domain->dev_input->type = CIM_RES_TYPE_INPUT; domain->dev_input->dev.input.type = strdup("mouse"); if (domain->type == DOMAIN_XENPV) { -- 1.7.9.5

On 09/05/2013 11:36 AM, Viktor Mihajlovski wrote:
The default graphics and input devices were built without their resource types being set correctly. This has not hurted yet. Future changes will however require that the device resource type is matching the actual device type.
Signed-off-by: Viktor Mihajlovski <mihajlov@linux.vnet.ibm.com> Reviewed-by: Boris Fiuczynski <fiuczy@linux.vnet.ibm.com> --- src/Virt_VirtualSystemManagementService.c | 2 ++ 1 file changed, 2 insertions(+)
ACK John

From: Thilo Boehm <tboehm@linux.vnet.ibm.com> Representing console devices was very limited with the previous approach using a special graphical display. For instance it was not possible to define different target types (serial, virtio, sclp) nor to exploit all source types (pty, file, tcp, ...) available in libvirt. With the following new RASD classes it is possible to define real console resources: KVM_ConsoleResouceAllocationSettingData Xen_ConsoleResouceAllocationSettingData LXC_ConsoleResouceAllocationSettingData Signed-off-by: Thilo Boehm <tboehm@linux.vnet.ibm.com> Signed-off-by: Viktor Mihajlovski <mihajlov@linux.vnet.ibm.com> Reviewed-by: Boris Fiuczynski <fiuczy@linux.vnet.ibm.com> --- schema/ResourceAllocationSettingData.mof | 247 ++++++++++++++++++++- schema/ResourceAllocationSettingData.registration | 5 +- 2 files changed, 250 insertions(+), 2 deletions(-) diff --git a/schema/ResourceAllocationSettingData.mof b/schema/ResourceAllocationSettingData.mof index 871ab04..8974d83 100644 --- a/schema/ResourceAllocationSettingData.mof +++ b/schema/ResourceAllocationSettingData.mof @@ -1,4 +1,4 @@ -// Copyright IBM Corp. 2007 +// Copyright IBM Corp. 2007, 2013 [Description ("Xen virtual disk configuration"), Provider("cmpi::Virt_RASD") @@ -445,3 +445,248 @@ class KVM_StorageVolumeResourceAllocationSettingData : KVM_ResourceAllocationSet string AllocationUnits; }; +[Description ("KVM virtual character device"), + Provider("cmpi::Virt_RASD") +] +class KVM_CharacterResourceAllocationSettingData : KVM_ResourceAllocationSettingData +{ + [Description ("The type of resource in the source/host environment."), + ValueMap {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10"}, + Values {"null", "vc", "pty", "dev", "file", "pipe", + "stdio", "udp", "tcp", "unix", "spicevmc"}, + ModelCorrespondence {"KVM_CharacterResourceAllocationSettingData.SourcePath", + "KVM_CharacterResourceAllocationSettingData.ConnectURL", + "KVM_CharacterResourceAllocationSettingData.BindURL"}] + uint16 SourceType; + + [Description ("If SourceType=4 ('file'),this is the full qualified file path. " + "The file is opened and all data sent to the character device " + "is written to the file. " + "If SourceType=2 ('pty'),this is the full qualified Pseudo TTY path. " + "A Pseudo TTY is allocated using /dev/ptmx. " + "If SourceType=3 ('dev'), this is the full qualified file path " + "to the underlying phsical character device. The device types must " + "match, eg the emulated serial port should only be connected to a " + "host serial port - don't connect a serial port to a parallel port. " + "If SourceType=5 ('pipe'), this is the full qualified file path " + "of a named pipe."), + ModelCorrespondence {"KVM_CharacterResourceAllocationSettingData.SourceType"}] + string SourcePath; + + [Description ("This URL describes the connection to a remote or local location " + "where the character devices acts as a client." + "To use a literal IPv6 address in the URI, the literal address should be " + "enclosed in '[' and ']' characters. " + "If SourceType=7 ('udp'), this is defines a udp remote host and port connection " + "to send packages. That the character device acts as a UDP netconsole service, " + "sending and receiving packets, the BindURL property must also be defined. " + "This is a lossy service. " + "Only 'udp' is valid for the protocol part of the URI. " + "Format of the URL: <protocol>://<host>:<port>. e.g. udp://0.0.0.0:2245 " + "If SourceType=8 ('tcp'), this is defines a remote host and port connection. " + "The protocol part of the URI can be: 'raw', 'telnet', 'telnets', 'tls'. " + "Format of the URL: <protocol>://<host>:<port>. e.g. raw://[3ffe:2a00:100:7031::1]:2245 " + "If SourceType=9 ('unix'), this is defined the full qualified file path " + "of a Unix domain socket. Only 'file' is valid for the protocol part of the URI. " + "Format of the URL: file://<full qualified file path>. " + "e.g. file:///tmp/console-out"), + ModelCorrespondence {"KVM_CharacterResourceAllocationSettingData.SourceType"}] + string ConnectURL; + + [Description ("This URL describes the connection to a remote or local location " + "where the character devices acts as a server. " + "To use a literal IPv6 address in the URI, the literal address should be " + "enclosed in '[' and ']' characters. " + "If SourceType=7 ('udp'), this is defines a udp remote host and port connection " + "to receive packages. That the character device acts as a UDP netconsole service, " + "sending and receiving packets, the ConnectURL property must also be defined. " + "This is a lossy service. " + "Only 'udp' is valid for the protocol part of the URI. " + "Format of the URL: <protocol>://<host>:<port>. e.g. udp://0.0.0.0:2245 " + "If SourceType=8 ('tcp'), this is defines a remote host and port connection. " + "The protocol part of the URI can be: 'raw', 'telnet', 'telnets', 'tls'. " + "Format of the URL: <protocol>://<host>:<port>. e.g. raw://[3ffe:2a00:100:7031::1]:2245 " + "If SourceType=9 ('unix'), this is defined the full qualified file path " + "of a Unix domain socket. Only 'file' is valid for the protocol part of the URI. " + "Format of the URL: file://<full qualified file path>. " + "e.g. file:///tmp/console-in"), + ModelCorrespondence {"KVM_CharacterResourceAllocationSettingData.SourceType"}] + string BindURL; +}; + + +[Description ("KVM virtual console device. It is identified by: " + "CIM_ResourceAllocationSettingData.ResourceType=1 ( 'Other' ) and " + "CIM_ResourceAllocationSettingData.OtherResourceType='console'"), + Provider("cmpi::Virt_RASD") +] +class KVM_ConsoleResourceAllocationSettingData : KVM_CharacterResourceAllocationSettingData +{ + [Description ("The type of the console in the target/guest environment.")] + string TargetType; +}; + + + +[Description ("Xen virtual character device"), + Provider("cmpi::Virt_RASD") +] +class Xen_CharacterResourceAllocationSettingData : Xen_ResourceAllocationSettingData +{ + [Description ("The type of resource in the source/host environment."), + ValueMap {"0","1", "2", "3", "4", "5", "6", "7", "8", "9", "10"}, + Values {"null", "vc", "pty", "dev", "file", "pipe", + "stdio", "udp", "tcp", "unix", "spicevmc"}, + ModelCorrespondence {"Xen_CharacterResourceAllocationSettingData.SourcePath", + "Xen_CharacterResourceAllocationSettingData.ConnectURL", + "Xen_CharacterResourceAllocationSettingData.BindURL"}] + uint16 SourceType; + + [Description ("If SourceType=4 ('file'),this is the full qualified file path. " + "The file is opened and all data sent to the character device " + "is written to the file. " + "If SourceType=2 ('pty'),this is the full qualified Pseudo TTY path. " + "A Pseudo TTY is allocated using /dev/ptmx. " + "If SourceType=3 ('dev'), this is the full qualified file path " + "to the underlying phsical character device. The device types must " + "match, eg the emulated serial port should only be connected to a " + "host serial port - don't connect a serial port to a parallel port. " + "If SourceType=5 ('pipe'), this is the full qualified file path " + "of a named pipe."), + ModelCorrespondence {"Xen_CharacterResourceAllocationSettingData.SourceType"}] + string SourcePath; + + [Description ("This URL describes the connection to a remote or local location " + "where the character devices acts as a client." + "To use a literal IPv6 address in the URI, the literal address should be " + "enclosed in '[' and ']' characters. " + "If SourceType=7 ('udp'), this is defines a udp remote host and port connection " + "to send packages. That the character device acts as a UDP netconsole service, " + "sending and receiving packets, the BindURL property must also be defined. " + "This is a lossy service. " + "Only 'udp' is valid for the protocol part of the URI. " + "Format of the URL: <protocol>://<host>:<port>. e.g. udp://0.0.0.0:2245 " + "If SourceType=8 ('tcp'), this is defines a remote host and port connection. " + "The protocol part of the URI can be: 'raw', 'telnet', 'telnets', 'tls'. " + "Format of the URL: <protocol>://<host>:<port>. e.g. raw://[3ffe:2a00:100:7031::1]:2245 " + "If SourceType=9 ('unix'), this is defined the full qualified file path " + "of a Unix domain socket. Only 'file' is valid for the protocol part of the URI. " + "Format of the URL: file://<full qualified file path>. " + "e.g. file:///tmp/console-out"), + ModelCorrespondence {"Xen_CharacterResourceAllocationSettingData.SourceType"}] + string ConnectURL; + + [Description ("This URL describes the connection to a remote or local location " + "where the character devices acts as a server. " + "To use a literal IPv6 address in the URI, the literal address should be " + "enclosed in '[' and ']' characters. " + "If SourceType=7 ('udp'), this is defines a udp remote host and port connection " + "to receive packages. That the character device acts as a UDP netconsole service, " + "sending and receiving packets, the ConnectURL property must also be defined. " + "This is a lossy service. " + "Only 'udp' is valid for the protocol part of the URI. " + "Format of the URL: <protocol>://<host>:<port>. e.g. udp://0.0.0.0:2245 " + "If SourceType=8 ('tcp'), this is defines a remote host and port connection. " + "The protocol part of the URI can be: 'raw', 'telnet', 'telnets', 'tls'. " + "Format of the URL: <protocol>://<host>:<port>. e.g. raw://[3ffe:2a00:100:7031::1]:2245 " + "If SourceType=9 ('unix'), this is defined the full qualified file path " + "of a Unix domain socket. Only 'file' is valid for the protocol part of the URI. " + "Format of the URL: file://<full qualified file path>. " + "e.g. file:///tmp/console-in"), + ModelCorrespondence {"Xen_CharacterResourceAllocationSettingData.SourceType"}] + string BindURL; +}; + + +[Description ("Xen virtual console device. It is identified by: " + "CIM_ResourceAllocationSettingData.ResourceType=1 ( 'Other' ) and " + "CIM_ResourceAllocationSettingData.OtherResourceType='console'"), + Provider("cmpi::Virt_RASD") +] +class Xen_ConsoleResourceAllocationSettingData : Xen_CharacterResourceAllocationSettingData +{ + [Description ( "The type of the console in the target/guest environment.")] + string TargetType; +}; + +[Description ("LXC virtual character device"), + Provider("cmpi::Virt_RASD") +] +class LXC_CharacterResourceAllocationSettingData : LXC_ResourceAllocationSettingData +{ + [Description ("The type of resource in the source/host environment."), + ValueMap {"0","1", "2", "3", "4", "5", "6", "7", "8", "9", "10"}, + Values {"null", "vc", "pty", "dev", "file", "pipe", + "stdio", "udp", "tcp", "unix", "spicevmc"}, + ModelCorrespondence {"LXC_CharacterResourceAllocationSettingData.SourcePath", + "LXC_CharacterResourceAllocationSettingData.ConnectURL", + "LXC_CharacterResourceAllocationSettingData.BindURL"}] + uint16 SourceType; + + [Description ("If SourceType=4 ('file'),this is the full qualified file path. " + "The file is opened and all data sent to the character device " + "is written to the file. " + "If SourceType=2 ('pty'),this is the full qualified Pseudo TTY path. " + "A Pseudo TTY is allocated using /dev/ptmx. " + "If SourceType=3 ('dev'), this is the full qualified file path " + "to the underlying phsical character device. The device types must " + "match, eg the emulated serial port should only be connected to a " + "host serial port - don't connect a serial port to a parallel port. " + "If SourceType=5 ('pipe'), this is the full qualified file path " + "of a named pipe."), + ModelCorrespondence {"LXC_CharacterResourceAllocationSettingData.SourceType"}] + string SourcePath; + + [Description ("This URL describes the connection to a remote or local location " + "where the character devices acts as a client." + "To use a literal IPv6 address in the URI, the literal address should be " + "enclosed in '[' and ']' characters. " + "If SourceType=7 ('udp'), this is defines a udp remote host and port connection " + "to send packages. That the character device acts as a UDP netconsole service, " + "sending and receiving packets, the BindURL property must also be defined. " + "This is a lossy service. " + "Only 'udp' is valid for the protocol part of the URI. " + "Format of the URL: <protocol>://<host>:<port>. e.g. udp://0.0.0.0:2245 " + "If SourceType=8 ('tcp'), this is defines a remote host and port connection. " + "The protocol part of the URI can be: 'raw', 'telnet', 'telnets', 'tls'. " + "Format of the URL: <protocol>://<host>:<port>. e.g. raw://[3ffe:2a00:100:7031::1]:2245 " + "If SourceType=9 ('unix'), this is defined the full qualified file path " + "of a Unix domain socket. Only 'file' is valid for the protocol part of the URI. " + "Format of the URL: file://<full qualified file path>. " + "e.g. file:///tmp/console-out"), + ModelCorrespondence {"LXC_CharacterResourceAllocationSettingData.SourceType"}] + string ConnectURL; + + [Description ("This URL describes the connection to a remote or local location " + "where the character devices acts as a server. " + "To use a literal IPv6 address in the URI, the literal address should be " + "enclosed in '[' and ']' characters. " + "If SourceType=7 ('udp'), this is defines a udp remote host and port connection " + "to receive packages. That the character device acts as a UDP netconsole service, " + "sending and receiving packets, the ConnectURL property must also be defined. " + "This is a lossy service. " + "Only 'udp' is valid for the protocol part of the URI. " + "Format of the URL: <protocol>://<host>:<port>. e.g. udp://0.0.0.0:2245 " + "If SourceType=8 ('tcp'), this is defines a remote host and port connection. " + "The protocol part of the URI can be: 'raw', 'telnet', 'telnets', 'tls'. " + "Format of the URL: <protocol>://<host>:<port>. e.g. raw://[3ffe:2a00:100:7031::1]:2245 " + "If SourceType=9 ('unix'), this is defined the full qualified file path " + "of a Unix domain socket. Only 'file' is valid for the protocol part of the URI. " + "Format of the URL: file://<full qualified file path>. " + "e.g. file:///tmp/console-in"), + ModelCorrespondence {"LXC_CharacterResourceAllocationSettingData.SourceType"}] + string BindURL; +}; + + +[Description ("LXC virtual console device. It is identified by: " + "CIM_ResourceAllocationSettingData.ResourceType=1 ( 'Other' ) and " + "CIM_ResourceAllocationSettingData.OtherResourceType='console'"), + Provider("cmpi::Virt_RASD") +] +class LXC_ConsoleResourceAllocationSettingData : LXC_CharacterResourceAllocationSettingData +{ + [Description ("The type of the console in the target/guest environment.")] + string TargetType; +}; + diff --git a/schema/ResourceAllocationSettingData.registration b/schema/ResourceAllocationSettingData.registration index 2747f91..b969bfe 100644 --- a/schema/ResourceAllocationSettingData.registration +++ b/schema/ResourceAllocationSettingData.registration @@ -1,4 +1,4 @@ -# Copyright IBM Corp. 2007 +# Copyright IBM Corp. 2007, 2013 # Classname Namespace ProviderName ProviderModule ProviderTypes Xen_DiskResourceAllocationSettingData root/virt Virt_RASD Virt_RASD instance Xen_NetResourceAllocationSettingData root/virt Virt_RASD Virt_RASD instance @@ -6,14 +6,17 @@ Xen_ProcResourceAllocationSettingData root/virt Virt_RASD Virt_RASD instance Xen_MemResourceAllocationSettingData root/virt Virt_RASD Virt_RASD instance Xen_GraphicsResourceAllocationSettingData root/virt Virt_RASD Virt_RASD instance Xen_InputResourceAllocationSettingData root/virt Virt_RASD Virt_RASD instance +Xen_ConsoleResourceAllocationSettingData root/virt Virt_RASD Virt_RASD instance KVM_DiskResourceAllocationSettingData root/virt Virt_RASD Virt_RASD instance KVM_NetResourceAllocationSettingData root/virt Virt_RASD Virt_RASD instance KVM_ProcResourceAllocationSettingData root/virt Virt_RASD Virt_RASD instance KVM_MemResourceAllocationSettingData root/virt Virt_RASD Virt_RASD instance KVM_GraphicsResourceAllocationSettingData root/virt Virt_RASD Virt_RASD instance KVM_InputResourceAllocationSettingData root/virt Virt_RASD Virt_RASD instance +KVM_ConsoleResourceAllocationSettingData root/virt Virt_RASD Virt_RASD instance LXC_MemResourceAllocationSettingData root/virt Virt_RASD Virt_RASD instance LXC_DiskResourceAllocationSettingData root/virt Virt_RASD Virt_RASD instance LXC_ProcResourceAllocationSettingData root/virt Virt_RASD Virt_RASD instance LXC_GraphicsResourceAllocationSettingData root/virt Virt_RASD Virt_RASD instance LXC_InputResourceAllocationSettingData root/virt Virt_RASD Virt_RASD instance +LXC_ConsoleResourceAllocationSettingData root/virt Virt_RASD Virt_RASD instance -- 1.7.9.5

On 09/05/2013 11:36 AM, Viktor Mihajlovski wrote:
From: Thilo Boehm <tboehm@linux.vnet.ibm.com>
Representing console devices was very limited with the previous approach using a special graphical display. For instance it was not possible to define different target types (serial, virtio, sclp) nor to exploit all source types (pty, file, tcp, ...) available in libvirt.
With the following new RASD classes it is possible to define real console resources: KVM_ConsoleResouceAllocationSettingData Xen_ConsoleResouceAllocationSettingData LXC_ConsoleResouceAllocationSettingData
Signed-off-by: Thilo Boehm <tboehm@linux.vnet.ibm.com> Signed-off-by: Viktor Mihajlovski <mihajlov@linux.vnet.ibm.com> Reviewed-by: Boris Fiuczynski <fiuczy@linux.vnet.ibm.com> --- schema/ResourceAllocationSettingData.mof | 247 ++++++++++++++++++++- schema/ResourceAllocationSettingData.registration | 5 +- 2 files changed, 250 insertions(+), 2 deletions(-)
ACK, but I will squash this with patch 5 when I push - I also will remove an empty line at the end of the .mof file as 'git am' complained. Cranky tools! John

From: Thilo Boehm <tboehm@linux.vnet.ibm.com> C definitions for the console source types, defining the representation of the consoles in the hypervisor host. Includes mapping from and to string representations. Signed-off-by: Thilo Boehm <tboehm@linux.vnet.ibm.com> Signed-off-by: Viktor Mihajlovski <mihajlov@linux.vnet.ibm.com> Reviewed-by: Boris Fiuczynski <fiuczy@linux.vnet.ibm.com> --- src/svpc_types.h | 97 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 96 insertions(+), 1 deletion(-) diff --git a/src/svpc_types.h b/src/svpc_types.h index 99dd56f..2e4d73f 100644 --- a/src/svpc_types.h +++ b/src/svpc_types.h @@ -1,5 +1,5 @@ /* - * Copyright IBM Corp. 2007 + * Copyright IBM Corp. 2007, 2013 * * Authors: * Dan Smith <danms@us.ibm.com> @@ -167,5 +167,100 @@ enum CIM_op_status { CIM_OP_STATUS_POWER_MODE = 18, }; +/* emum for the Character device Source resource types */ +enum CIM_chardev_source_type { + CIM_CHARDEV_SOURCE_TYPE_NULL = 0, + CIM_CHARDEV_SOURCE_TYPE_VC = 1, + CIM_CHARDEV_SOURCE_TYPE_PTY = 2, + CIM_CHARDEV_SOURCE_TYPE_DEV = 3, + CIM_CHARDEV_SOURCE_TYPE_FILE = 4, + CIM_CHARDEV_SOURCE_TYPE_PIPE = 5, + CIM_CHARDEV_SOURCE_TYPE_STDIO = 6, + CIM_CHARDEV_SOURCE_TYPE_UDP = 7, + CIM_CHARDEV_SOURCE_TYPE_TCP = 8, + CIM_CHARDEV_SOURCE_TYPE_UNIXSOCK = 9, + CIM_CHARDEV_SOURCE_TYPE_SPICEVMC = 10, + /* please insert new source types above */ + CIM_CHARDEV_SOURCE_TYPE_INVALIDTYPE, + CIM_CHARDEV_SOURCE_TYPE_UNKNOWN = 32768, +}; + +static inline int chardev_source_type_StrToID(const char *type_str) +{ + int rc = CIM_CHARDEV_SOURCE_TYPE_UNKNOWN; + + if (type_str == NULL) + return rc; + + if (STREQC(type_str, "null")) + rc = CIM_CHARDEV_SOURCE_TYPE_NULL; + else if (STREQC(type_str, "vc")) + rc = CIM_CHARDEV_SOURCE_TYPE_VC; + else if (STREQC(type_str, "pty")) + rc = CIM_CHARDEV_SOURCE_TYPE_PTY; + else if (STREQC(type_str, "dev")) + rc = CIM_CHARDEV_SOURCE_TYPE_DEV; + else if (STREQC(type_str, "file")) + rc = CIM_CHARDEV_SOURCE_TYPE_FILE; + else if (STREQC(type_str, "pipe")) + rc = CIM_CHARDEV_SOURCE_TYPE_PIPE; + else if (STREQC(type_str, "stdio")) + rc = CIM_CHARDEV_SOURCE_TYPE_STDIO; + else if (STREQC(type_str, "udp")) + rc = CIM_CHARDEV_SOURCE_TYPE_UDP; + else if (STREQC(type_str, "tcp")) + rc = CIM_CHARDEV_SOURCE_TYPE_TCP; + else if (STREQC(type_str, "unix")) + rc = CIM_CHARDEV_SOURCE_TYPE_UNIXSOCK; + else if (STREQC(type_str, "spicevmc")) + rc = CIM_CHARDEV_SOURCE_TYPE_SPICEVMC; + + return rc; +} + +static inline const char* chardev_source_type_IDToStr(int type) +{ + char *type_str = NULL; + + switch (type) + { + case CIM_CHARDEV_SOURCE_TYPE_NULL: + type_str = "null"; + break; + case CIM_CHARDEV_SOURCE_TYPE_VC: + type_str = "vc"; + break; + case CIM_CHARDEV_SOURCE_TYPE_PTY: + type_str = "pty"; + break; + case CIM_CHARDEV_SOURCE_TYPE_DEV: + type_str = "dev"; + break; + case CIM_CHARDEV_SOURCE_TYPE_FILE: + type_str = "file"; + break; + case CIM_CHARDEV_SOURCE_TYPE_PIPE: + type_str = "pipe"; + break; + case CIM_CHARDEV_SOURCE_TYPE_STDIO: + type_str = "stdio"; + break; + case CIM_CHARDEV_SOURCE_TYPE_UDP: + type_str = "udp"; + break; + case CIM_CHARDEV_SOURCE_TYPE_TCP: + type_str = "tcp"; + break; + case CIM_CHARDEV_SOURCE_TYPE_UNIXSOCK: + type_str = "unix"; + break; + case CIM_CHARDEV_SOURCE_TYPE_SPICEVMC: + type_str = "spicevmc"; + break; + default: + break; + } + return type_str; +} #endif -- 1.7.9.5

On 09/05/2013 11:36 AM, Viktor Mihajlovski wrote:
From: Thilo Boehm <tboehm@linux.vnet.ibm.com>
C definitions for the console source types, defining the representation of the consoles in the hypervisor host. Includes mapping from and to string representations.
Signed-off-by: Thilo Boehm <tboehm@linux.vnet.ibm.com> Signed-off-by: Viktor Mihajlovski <mihajlov@linux.vnet.ibm.com> Reviewed-by: Boris Fiuczynski <fiuczy@linux.vnet.ibm.com> --- src/svpc_types.h | 97 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 96 insertions(+), 1 deletion(-)
ACK John

From: Thilo Boehm <tboehm@linux.vnet.ibm.com> Added data types for the representation of console devices and their source type specific properties. Further, implemented libvirt XML parsing and generation of console device XML. Signed-off-by: Thilo Boehm <tboehm@linux.vnet.ibm.com> Signed-off-by: Viktor Mihajlovski <mihajlov@linux.vnet.ibm.com> Reviewed-by: Boris Fiuczynski <fiuczy@linux.vnet.ibm.com> --- libxkutil/device_parsing.c | 316 ++++++++++++++++++++++++++++++++++++++++++-- libxkutil/device_parsing.h | 43 +++++- libxkutil/xmlgen.c | 191 +++++++++++++++++++++++++- src/svpc_types.h | 5 +- 4 files changed, 543 insertions(+), 12 deletions(-) diff --git a/libxkutil/device_parsing.c b/libxkutil/device_parsing.c index fa9f998..06acbac 100644 --- a/libxkutil/device_parsing.c +++ b/libxkutil/device_parsing.c @@ -1,5 +1,5 @@ /* - * Copyright IBM Corp. 2007 + * Copyright IBM Corp. 2007, 2013 * * Authors: * Dan Smith <danms@us.ibm.com> @@ -41,6 +41,11 @@ #define NET_XPATH (xmlChar *)"/domain/devices/interface" #define EMU_XPATH (xmlChar *)"/domain/devices/emulator" #define MEM_XPATH (xmlChar *)"/domain/memory | /domain/currentMemory" +#define CONSOLE_XPATH (xmlChar *)"/domain/devices/console" +/* + * To be backward compatible, serial and console is + * still part of the graphics. + */ #define GRAPHICS_XPATH (xmlChar *)"/domain/devices/graphics | "\ "/domain/devices/console | /domain/devices/serial" #define INPUT_XPATH (xmlChar *)"/domain/devices/input" @@ -50,6 +55,11 @@ #define MAX(a,b) (((a)>(b))?(a):(b)) +#define DUP_FIELD(d, s, f) do { \ + if ((s)->f != NULL) \ + (d)->f = strdup((s)->f); \ + } while (0); + /* Device parse function */ typedef int (*dev_parse_func_t)(xmlNode *, struct virt_device **); @@ -133,6 +143,140 @@ static void cleanup_graphics_device(struct graphics_device *dev) free(dev->type); } +static void cleanup_path_device(struct path_device *dev) +{ + if (dev == NULL) + return; + + free(dev->path); + +} + +static void cleanup_unixsock_device(struct unixsock_device *dev) +{ + if (dev == NULL) + return; + + free(dev->path); + free(dev->mode); + +} + +static void cleanup_tcp_device(struct tcp_device *dev) +{ + if (dev == NULL) + return; + + free(dev->mode); + free(dev->protocol); + free(dev->host); + free(dev->service); + +} + +static void cleanup_udp_device(struct udp_device *dev) +{ + if (dev == NULL) + return; + + free(dev->bind_host); + free(dev->bind_service); + free(dev->connect_host); + free(dev->connect_service); +}; + +static void cleanup_console_device(struct console_device *dev) +{ + if (dev == NULL) + return; + + switch (dev->source_type) + { + case CIM_CHARDEV_SOURCE_TYPE_PTY: + cleanup_path_device(&dev->source_dev.pty); + break; + case CIM_CHARDEV_SOURCE_TYPE_DEV: + cleanup_path_device(&dev->source_dev.dev); + break; + case CIM_CHARDEV_SOURCE_TYPE_FILE: + cleanup_path_device(&dev->source_dev.file); + break; + case CIM_CHARDEV_SOURCE_TYPE_PIPE: + cleanup_path_device(&dev->source_dev.pipe); + break; + case CIM_CHARDEV_SOURCE_TYPE_UNIXSOCK: + cleanup_unixsock_device(&dev->source_dev.unixsock); + break; + case CIM_CHARDEV_SOURCE_TYPE_UDP: + cleanup_udp_device(&dev->source_dev.udp); + break; + case CIM_CHARDEV_SOURCE_TYPE_TCP: + cleanup_tcp_device(&dev->source_dev.tcp); + break; + default: + /* Nothing to do for : + CIM_CHARDEV_SOURCE_TYPE_STDIO + CIM_CHARDEV_SOURCE_TYPE_NULL + CIM_CHARDEV_SOURCE_TYPE_VC + CIM_CHARDEV_SOURCE_TYPE_SPICEVMC + */ + break; + } + + dev->source_type = 0; + free(dev->target_type); + memset(&dev->source_dev, 0, sizeof(dev->source_dev)); +}; + +static void console_device_dup(struct console_device *t, + struct console_device *s) +{ + cleanup_console_device(t); + + t->source_type = s->source_type; + DUP_FIELD(t, s, target_type); + + switch (s->source_type) + { + case CIM_CHARDEV_SOURCE_TYPE_PTY: + DUP_FIELD(t, s, source_dev.pty.path); + break; + case CIM_CHARDEV_SOURCE_TYPE_DEV: + DUP_FIELD(t, s, source_dev.dev.path); + break; + case CIM_CHARDEV_SOURCE_TYPE_FILE: + DUP_FIELD(t, s, source_dev.file.path); + break; + case CIM_CHARDEV_SOURCE_TYPE_PIPE: + DUP_FIELD(t, s, source_dev.pipe.path); + break; + case CIM_CHARDEV_SOURCE_TYPE_UNIXSOCK: + DUP_FIELD(t, s, source_dev.unixsock.path); + DUP_FIELD(t, s, source_dev.unixsock.mode); + break; + case CIM_CHARDEV_SOURCE_TYPE_UDP: + DUP_FIELD(t, s, source_dev.udp.bind_host); + DUP_FIELD(t, s, source_dev.udp.bind_service); + DUP_FIELD(t, s, source_dev.udp.connect_host); + DUP_FIELD(t, s, source_dev.udp.connect_service); + break; + case CIM_CHARDEV_SOURCE_TYPE_TCP: + DUP_FIELD(t, s, source_dev.tcp.mode); + DUP_FIELD(t, s, source_dev.tcp.protocol); + DUP_FIELD(t, s, source_dev.tcp.host); + DUP_FIELD(t, s, source_dev.tcp.service); + break; + default: + /* Nothing to do for : + CIM_CHARDEV_SOURCE_TYPE_STDIO + CIM_CHARDEV_SOURCE_TYPE_NULL + CIM_CHARDEV_SOURCE_TYPE_VC + CIM_CHARDEV_SOURCE_TYPE_SPICEVMC + */ + break; + } +} + static void cleanup_input_device(struct input_device *dev) { if (dev == NULL) @@ -157,6 +301,8 @@ void cleanup_virt_device(struct virt_device *dev) cleanup_graphics_device(&dev->dev.graphics); else if (dev->type == CIM_RES_TYPE_INPUT) cleanup_input_device(&dev->dev.input); + else if (dev->type == CIM_RES_TYPE_CONSOLE) + cleanup_console_device(&dev->dev.console); free(dev->id); @@ -613,6 +759,140 @@ static char *get_attr_value_default(xmlNode *node, char *attrname, return ret; } +static int parse_console_device(xmlNode *node, struct virt_device **vdevs) +{ + struct virt_device *vdev = NULL; + struct console_device *cdev = NULL; + char *source_type_str = NULL; + char *target_port_ID = NULL; + char *udp_source_mode = NULL; + + xmlNode *child = NULL; + + vdev = calloc(1, sizeof(*vdev)); + if (vdev == NULL) + goto err; + + cdev = &(vdev->dev.console); + + source_type_str = get_attr_value(node, "type"); + if (source_type_str == NULL) + goto err; + CU_DEBUG("console device type = %s", source_type_str); + + cdev->source_type = chardev_source_type_StrToID(source_type_str); + if (cdev->source_type == CIM_CHARDEV_SOURCE_TYPE_UNKNOWN) + goto err; + + CU_DEBUG("console device type ID = %d", cdev->source_type); + free(source_type_str); + + for (child = node->children; child != NULL; child = child->next) { + if (XSTREQ(child->name, "target")) { + cdev->target_type = get_attr_value(child, "type"); + CU_DEBUG("Console device target type = '%s'", + cdev->target_type); + target_port_ID = get_attr_value(child, "port"); + if (target_port_ID == NULL) + goto err; + } + + if (XSTREQ(child->name, "source")) { + switch (cdev->source_type) + { + case CIM_CHARDEV_SOURCE_TYPE_PTY: + cdev->source_dev.pty.path = + get_attr_value(child, "path"); + break; + case CIM_CHARDEV_SOURCE_TYPE_DEV: + cdev->source_dev.dev.path = + get_attr_value(child, "path"); + break; + case CIM_CHARDEV_SOURCE_TYPE_FILE: + cdev->source_dev.file.path = + get_attr_value(child, "path"); + break; + case CIM_CHARDEV_SOURCE_TYPE_PIPE: + cdev->source_dev.pipe.path = + get_attr_value(child, "path"); + break; + case CIM_CHARDEV_SOURCE_TYPE_UNIXSOCK: + cdev->source_dev.unixsock.mode = + get_attr_value(child, "mode"); + cdev->source_dev.unixsock.path = + get_attr_value(child, "path"); + break; + case CIM_CHARDEV_SOURCE_TYPE_UDP: + udp_source_mode = get_attr_value(child, "mode"); + if (udp_source_mode == NULL) + goto err; + if (STREQC(udp_source_mode, "bind")) { + cdev->source_dev.udp.bind_host = + get_attr_value(child, "host"); + cdev->source_dev.udp.bind_service = + get_attr_value(child, "service"); + } + else if (STREQC(udp_source_mode, "connect")) { + cdev->source_dev.udp.connect_host = + get_attr_value(child, "host"); + cdev->source_dev.udp.connect_service = + get_attr_value(child, "service"); + } + else { + CU_DEBUG("unknown udp mode: %s", + udp_source_mode); + goto err; + } + free(udp_source_mode); + break; + case CIM_CHARDEV_SOURCE_TYPE_TCP: + cdev->source_dev.tcp.mode = + get_attr_value(child, "mode"); + cdev->source_dev.tcp.host = + get_attr_value(child, "host"); + cdev->source_dev.tcp.service = + get_attr_value(child, "service"); + break; + + default: + /* Nothing to do for : + CIM_CHARDEV_SOURCE_TYPE_STDIO + CIM_CHARDEV_SOURCE_TYPE_NULL + CIM_CHARDEV_SOURCE_TYPE_VC + CIM_CHARDEV_SOURCE_TYPE_SPICEVMC + */ + break; + } + } + if ((cdev->source_type == CIM_CHARDEV_SOURCE_TYPE_TCP) + && XSTREQ(child->name, "protocol")) { + cdev->source_dev.tcp.protocol = + get_attr_value(child, "type"); + } + } + + vdev->type = CIM_RES_TYPE_CONSOLE; + + if (-1 == asprintf(&vdev->id, "charconsole:%s", target_port_ID)) { + CU_DEBUG("Failed to create charconsole id string"); + goto err; + } + + *vdevs = vdev; + free(target_port_ID); + + return 1; + + err: + free(source_type_str); + free(target_port_ID); + free(udp_source_mode); + cleanup_console_device(cdev); + free(vdev); + + return 0; +} + static int parse_graphics_device(xmlNode *node, struct virt_device **vdevs) { struct virt_device *vdev = NULL; @@ -664,8 +944,20 @@ static int parse_graphics_device(xmlNode *node, struct virt_device **vdevs) child = child->next) { if (XSTREQ(child->name, "source")) gdev->dev.vnc.host = get_attr_value(child, "path"); - else if (XSTREQ(child->name, "target")) - gdev->dev.vnc.port = get_attr_value(child, "port"); + else if (XSTREQ(child->name, "target")) { + gdev->dev.vnc.port = + get_attr_value(child, "port"); + /* The graphics pty console can only be a + virtio console. If 'type' is not set in the + xml, the default of libvirt is virtio.*/ + char *t_type = get_attr_value(child, "type"); + if (t_type != NULL && !STREQC(t_type, "virtio")) { + CU_DEBUG("Not a pty-virtio graphics console"); + free(t_type); + goto err; + } + free(t_type); + } } } else { @@ -841,6 +1133,11 @@ static int parse_devices(const char *xml, struct virt_device **_list, int type) func = &parse_graphics_device; break; + case CIM_RES_TYPE_CONSOLE: + xpathstr = CONSOLE_XPATH; + func = &parse_console_device; + break; + case CIM_RES_TYPE_INPUT: xpathstr = INPUT_XPATH; func = &parse_input_device; @@ -876,11 +1173,6 @@ static int parse_devices(const char *xml, struct virt_device **_list, int type) return count; } -#define DUP_FIELD(d, s, f) do { \ - if ((s)->f != NULL) \ - (d)->f = strdup((s)->f); \ - } while (0); - struct virt_device *virt_device_dup(struct virt_device *_dev) { struct virt_device *dev; @@ -939,8 +1231,10 @@ struct virt_device *virt_device_dup(struct virt_device *_dev) } else if (dev->type == CIM_RES_TYPE_INPUT) { DUP_FIELD(dev, _dev, dev.input.type); DUP_FIELD(dev, _dev, dev.input.bus); + } else if (dev->type == CIM_RES_TYPE_CONSOLE) { + console_device_dup(&dev->dev.console, + &_dev->dev.console); } - return dev; } @@ -1299,6 +1593,9 @@ int get_dominfo_from_xml(const char *xml, struct domain **dominfo) (*dominfo)->dev_graphics_ct = parse_devices(xml, &(*dominfo)->dev_graphics, CIM_RES_TYPE_GRAPHICS); + (*dominfo)->dev_console_ct = parse_devices(xml, + &(*dominfo)->dev_console, + CIM_RES_TYPE_CONSOLE); (*dominfo)->dev_input_ct = parse_devices(xml, &(*dominfo)->dev_input, CIM_RES_TYPE_INPUT); @@ -1396,6 +1693,7 @@ void cleanup_dominfo(struct domain **dominfo) cleanup_virt_devices(&dom->dev_vcpu, dom->dev_vcpu_ct); cleanup_virt_devices(&dom->dev_graphics, dom->dev_graphics_ct); cleanup_virt_devices(&dom->dev_input, dom->dev_input_ct); + cleanup_virt_devices(&dom->dev_console, dom->dev_console_ct); free(dom); diff --git a/libxkutil/device_parsing.h b/libxkutil/device_parsing.h index 14e49b8..2803d6a 100644 --- a/libxkutil/device_parsing.h +++ b/libxkutil/device_parsing.h @@ -1,5 +1,5 @@ /* - * Copyright IBM Corp. 2007 + * Copyright IBM Corp. 2007, 2013 * * Authors: * Dan Smith <danms@us.ibm.com> @@ -111,6 +111,43 @@ struct graphics_device { } dev; }; +struct path_device { + char *path; +}; + +struct unixsock_device { + char *path; + char *mode; +}; + +struct tcp_device { + char *mode; + char *protocol; + char *host; + char *service; +}; + +struct udp_device { + char *bind_host; + char *bind_service; + char *connect_host; + char *connect_service; +}; + +struct console_device { + uint16_t source_type; + union { + struct path_device file; + struct path_device pty; + struct path_device dev; + struct path_device pipe; + struct unixsock_device unixsock; + struct tcp_device tcp; + struct udp_device udp; + } source_dev; + char *target_type; +}; + struct input_device { char *type; char *bus; @@ -125,6 +162,7 @@ struct virt_device { struct vcpu_device vcpu; struct emu_device emu; struct graphics_device graphics; + struct console_device console; struct input_device input; } dev; char *id; @@ -182,6 +220,9 @@ struct domain { struct virt_device *dev_graphics; int dev_graphics_ct; + struct virt_device *dev_console; + int dev_console_ct; + struct virt_device *dev_emu; struct virt_device *dev_input; diff --git a/libxkutil/xmlgen.c b/libxkutil/xmlgen.c index 2ca2341..45bfb04 100644 --- a/libxkutil/xmlgen.c +++ b/libxkutil/xmlgen.c @@ -1,5 +1,5 @@ /* - * Copyright IBM Corp. 2007 + * Copyright IBM Corp. 2007, 2013 * * Authors: * Dan Smith <danms@us.ibm.com> @@ -42,6 +42,189 @@ typedef const char *(*devfn_t)(xmlNodePtr node, struct domain *dominfo); typedef const char *(*poolfn_t)(xmlNodePtr node, struct virt_pool *pool); typedef const char *(*resfn_t)(xmlNodePtr node, struct virt_pool_res *res); +static int _count_graphics_console_definitions(struct domain *dominfo) +{ + int i; + int num = 0; + + for (i = 0; i < dominfo->dev_graphics_ct; i++) { + struct virt_device *_dev = &dominfo->dev_graphics[i]; + if (_dev->type == CIM_RES_TYPE_UNKNOWN) + continue; + + struct graphics_device *dev = &_dev->dev.graphics; + + if (STREQC(dev->type, "console")) { + num++; + } + } + CU_DEBUG("Found %d console defintions in graphics devices.",num); + return num; + +} + +static const char *console_xml(xmlNodePtr root, struct domain *dominfo) +{ + int i; + xmlNodePtr console; + xmlNodePtr tmp; + int num_graphics_consol_def = 0; + int num_suppressed_console_def = 0; + + num_graphics_consol_def = _count_graphics_console_definitions(dominfo); + + for (i = 0; i < dominfo->dev_console_ct; i++) { + struct virt_device *_dev = &dominfo->dev_console[i]; + if (_dev->type == CIM_RES_TYPE_UNKNOWN) + continue; + + struct console_device *cdev = &_dev->dev.console; + + /* Due to backward compatibility, the graphics device handling + is still parsing consoles: + source = pty, target = virtio (which is the default target) + But the console device handling processes these kind of + consoles too. This would lead to a duplication of these + default consoles in the domain xml definition. + This code prevents the console handling of writing xml for + duplicate pty/virtio consoles which are written by the + graphics device handling. */ + if (cdev->source_type == CIM_CHARDEV_SOURCE_TYPE_PTY && + (cdev->target_type == NULL || + STREQC(cdev->target_type, "virtio"))) { + if (num_suppressed_console_def < + num_graphics_consol_def) { + num_suppressed_console_def++; + continue; + } + } + + console = xmlNewChild(root, NULL, BAD_CAST "console", NULL); + if (console == NULL) + return XML_ERROR; + + xmlNewProp(console, BAD_CAST "type", + BAD_CAST + chardev_source_type_IDToStr(cdev->source_type)); + + switch (cdev->source_type) { + case CIM_CHARDEV_SOURCE_TYPE_PTY: + /* The path property is not mandatory */ + if (cdev->source_dev.pty.path) { + tmp = xmlNewChild(console, NULL, + BAD_CAST "source", NULL); + if (tmp == NULL) + return XML_ERROR; + xmlNewProp(tmp, BAD_CAST "path", + BAD_CAST cdev->source_dev.pty.path); + } + break; + case CIM_CHARDEV_SOURCE_TYPE_DEV: + tmp = xmlNewChild(console, NULL, + BAD_CAST "source", NULL); + if (tmp == NULL) + return XML_ERROR; + xmlNewProp(tmp, BAD_CAST "path", + BAD_CAST cdev->source_dev.dev.path); + break; + case CIM_CHARDEV_SOURCE_TYPE_FILE: + tmp = xmlNewChild(console, NULL, + BAD_CAST "source", NULL); + if (tmp == NULL) + return XML_ERROR; + xmlNewProp(tmp, BAD_CAST "path", + BAD_CAST cdev->source_dev.file.path); + break; + case CIM_CHARDEV_SOURCE_TYPE_PIPE: + tmp = xmlNewChild(console, NULL, + BAD_CAST "source", NULL); + if (tmp == NULL) + return XML_ERROR; + xmlNewProp(tmp, BAD_CAST "path", + BAD_CAST cdev->source_dev.pipe.path); + break; + case CIM_CHARDEV_SOURCE_TYPE_UNIXSOCK: + tmp = xmlNewChild(console, NULL, + BAD_CAST "source", NULL); + if (tmp == NULL) + return XML_ERROR; + xmlNewProp(tmp, BAD_CAST "mode", + BAD_CAST cdev->source_dev.unixsock.mode); + xmlNewProp(tmp, BAD_CAST "path", + BAD_CAST cdev->source_dev.unixsock.path); + break; + case CIM_CHARDEV_SOURCE_TYPE_UDP: + tmp = xmlNewChild(console, NULL, + BAD_CAST "source", NULL); + if (tmp == NULL) + return XML_ERROR; + xmlNewProp(tmp, BAD_CAST "mode", BAD_CAST "bind"); + xmlNewProp(tmp, BAD_CAST "host", + BAD_CAST cdev->source_dev.udp.bind_host); + /* The service property is not mandatory */ + if (cdev->source_dev.udp.bind_service) + xmlNewProp(tmp, BAD_CAST "service", + BAD_CAST + cdev->source_dev.udp.bind_service); + + tmp = xmlNewChild(console, NULL, + BAD_CAST "source", NULL); + if (tmp == NULL) + return XML_ERROR; + xmlNewProp(tmp, BAD_CAST "mode", BAD_CAST "connect"); + xmlNewProp(tmp, BAD_CAST "host", + BAD_CAST cdev->source_dev.udp.connect_host); + /* The service property is not mandatory */ + if (cdev->source_dev.udp.connect_service) + xmlNewProp(tmp, BAD_CAST "service", + BAD_CAST + cdev->source_dev.udp.connect_service); + + break; + case CIM_CHARDEV_SOURCE_TYPE_TCP: + tmp = xmlNewChild(console, NULL, + BAD_CAST "source", NULL); + if (tmp == NULL) + return XML_ERROR; + xmlNewProp(tmp, BAD_CAST "mode", + BAD_CAST cdev->source_dev.tcp.mode); + xmlNewProp(tmp, BAD_CAST "host", + BAD_CAST cdev->source_dev.tcp.host); + if (cdev->source_dev.tcp.service) + xmlNewProp(tmp, BAD_CAST "service", + BAD_CAST + cdev->source_dev.tcp.service); + if (cdev->source_dev.tcp.protocol) { + tmp = xmlNewChild(console, NULL, + BAD_CAST "protocol", NULL); + if (tmp == NULL) + return XML_ERROR; + xmlNewProp(tmp, BAD_CAST "type", + BAD_CAST cdev->source_dev.tcp.protocol); + } + break; + default: + /* Nothing to do for : + CIM_CHARDEV_SOURCE_TYPE_STDIO + CIM_CHARDEV_SOURCE_TYPE_NULL + CIM_CHARDEV_SOURCE_TYPE_VC + CIM_CHARDEV_SOURCE_TYPE_SPICEVMC + */ + break; + } + + if (cdev->target_type) { + tmp = xmlNewChild(console, NULL, + BAD_CAST "target", NULL); + if (tmp == NULL) + return XML_ERROR; + xmlNewProp(tmp, BAD_CAST "type", + BAD_CAST cdev->target_type); + } + } + return NULL; +} + static char *disk_block_xml(xmlNodePtr root, struct disk_device *dev) { xmlNodePtr disk; @@ -977,6 +1160,11 @@ char *device_to_xml(struct virt_device *_dev) dominfo->dev_graphics_ct = 1; dominfo->dev_graphics = dev; break; + case CIM_RES_TYPE_CONSOLE: + func = console_xml; + dominfo->dev_console_ct = 1; + dominfo->dev_console = dev; + break; case CIM_RES_TYPE_INPUT: func = input_xml; dominfo->dev_input_ct = 1; @@ -1017,6 +1205,7 @@ char *system_to_xml(struct domain *dominfo) &disk_xml, &net_xml, &input_xml, + &console_xml, &graphics_xml, &emu_xml, NULL diff --git a/src/svpc_types.h b/src/svpc_types.h index 2e4d73f..0f46a86 100644 --- a/src/svpc_types.h +++ b/src/svpc_types.h @@ -25,6 +25,7 @@ #define CIM_OPERATIONAL_STATUS 2 #define CIM_RES_TYPE_ALL 0 +#define CIM_RES_TYPE_OTHER 1 #define CIM_RES_TYPE_PROC 3 #define CIM_RES_TYPE_MEM 4 #define CIM_RES_TYPE_NET 10 @@ -34,8 +35,9 @@ #define CIM_RES_TYPE_INPUT 13 #define CIM_RES_TYPE_UNKNOWN 1000 #define CIM_RES_TYPE_IMAGE 32768 +#define CIM_RES_TYPE_CONSOLE 32769 -#define CIM_RES_TYPE_COUNT 6 +#define CIM_RES_TYPE_COUNT 7 const static int cim_res_types[CIM_RES_TYPE_COUNT] = {CIM_RES_TYPE_NET, CIM_RES_TYPE_DISK, @@ -43,6 +45,7 @@ const static int cim_res_types[CIM_RES_TYPE_COUNT] = CIM_RES_TYPE_PROC, CIM_RES_TYPE_GRAPHICS, CIM_RES_TYPE_INPUT, + CIM_RES_TYPE_CONSOLE, }; #define CIM_VSSD_RECOVERY_NONE 2 -- 1.7.9.5

On 09/05/2013 11:36 AM, Viktor Mihajlovski wrote:
From: Thilo Boehm <tboehm@linux.vnet.ibm.com>
Added data types for the representation of console devices and their source type specific properties. Further, implemented libvirt XML parsing and generation of console device XML.
Signed-off-by: Thilo Boehm <tboehm@linux.vnet.ibm.com> Signed-off-by: Viktor Mihajlovski <mihajlov@linux.vnet.ibm.com> Reviewed-by: Boris Fiuczynski <fiuczy@linux.vnet.ibm.com> --- libxkutil/device_parsing.c | 316 ++++++++++++++++++++++++++++++++++++++++++-- libxkutil/device_parsing.h | 43 +++++- libxkutil/xmlgen.c | 191 +++++++++++++++++++++++++- src/svpc_types.h | 5 +- 4 files changed, 543 insertions(+), 12 deletions(-)
diff --git a/libxkutil/device_parsing.c b/libxkutil/device_parsing.c index fa9f998..06acbac 100644 --- a/libxkutil/device_parsing.c +++ b/libxkutil/device_parsing.c @@ -1,5 +1,5 @@ /* - * Copyright IBM Corp. 2007 + * Copyright IBM Corp. 2007, 2013 * * Authors: * Dan Smith <danms@us.ibm.com> @@ -41,6 +41,11 @@ #define NET_XPATH (xmlChar *)"/domain/devices/interface" #define EMU_XPATH (xmlChar *)"/domain/devices/emulator" #define MEM_XPATH (xmlChar *)"/domain/memory | /domain/currentMemory" +#define CONSOLE_XPATH (xmlChar *)"/domain/devices/console" +/* + * To be backward compatible, serial and console is + * still part of the graphics. + */ #define GRAPHICS_XPATH (xmlChar *)"/domain/devices/graphics | "\ "/domain/devices/console | /domain/devices/serial" #define INPUT_XPATH (xmlChar *)"/domain/devices/input" @@ -50,6 +55,11 @@
#define MAX(a,b) (((a)>(b))?(a):(b))
+#define DUP_FIELD(d, s, f) do { \ + if ((s)->f != NULL) \ + (d)->f = strdup((s)->f); \ + } while (0); + /* Device parse function */ typedef int (*dev_parse_func_t)(xmlNode *, struct virt_device **);
@@ -133,6 +143,140 @@ static void cleanup_graphics_device(struct graphics_device *dev) free(dev->type); }
+static void cleanup_path_device(struct path_device *dev) +{ + if (dev == NULL) + return; + + free(dev->path); + +} + +static void cleanup_unixsock_device(struct unixsock_device *dev) +{ + if (dev == NULL) + return; + + free(dev->path); + free(dev->mode); + +} + +static void cleanup_tcp_device(struct tcp_device *dev) +{ + if (dev == NULL) + return; + + free(dev->mode); + free(dev->protocol); + free(dev->host); + free(dev->service); + +} + +static void cleanup_udp_device(struct udp_device *dev) +{ + if (dev == NULL) + return; + + free(dev->bind_host); + free(dev->bind_service); + free(dev->connect_host); + free(dev->connect_service); +}; + +static void cleanup_console_device(struct console_device *dev) +{ + if (dev == NULL) + return; + + switch (dev->source_type) + { + case CIM_CHARDEV_SOURCE_TYPE_PTY: + cleanup_path_device(&dev->source_dev.pty); + break; + case CIM_CHARDEV_SOURCE_TYPE_DEV: + cleanup_path_device(&dev->source_dev.dev); + break; + case CIM_CHARDEV_SOURCE_TYPE_FILE: + cleanup_path_device(&dev->source_dev.file); + break; + case CIM_CHARDEV_SOURCE_TYPE_PIPE: + cleanup_path_device(&dev->source_dev.pipe); + break; + case CIM_CHARDEV_SOURCE_TYPE_UNIXSOCK: + cleanup_unixsock_device(&dev->source_dev.unixsock); + break; + case CIM_CHARDEV_SOURCE_TYPE_UDP: + cleanup_udp_device(&dev->source_dev.udp); + break; + case CIM_CHARDEV_SOURCE_TYPE_TCP: + cleanup_tcp_device(&dev->source_dev.tcp); + break; + default: + /* Nothing to do for : + CIM_CHARDEV_SOURCE_TYPE_STDIO + CIM_CHARDEV_SOURCE_TYPE_NULL + CIM_CHARDEV_SOURCE_TYPE_VC + CIM_CHARDEV_SOURCE_TYPE_SPICEVMC + */ + break; + } + + dev->source_type = 0; + free(dev->target_type); + memset(&dev->source_dev, 0, sizeof(dev->source_dev)); +}; + +static void console_device_dup(struct console_device *t, + struct console_device *s) +{ + cleanup_console_device(t); + + t->source_type = s->source_type; + DUP_FIELD(t, s, target_type); + + switch (s->source_type) + { + case CIM_CHARDEV_SOURCE_TYPE_PTY: + DUP_FIELD(t, s, source_dev.pty.path); + break; + case CIM_CHARDEV_SOURCE_TYPE_DEV: + DUP_FIELD(t, s, source_dev.dev.path); + break; + case CIM_CHARDEV_SOURCE_TYPE_FILE: + DUP_FIELD(t, s, source_dev.file.path); + break; + case CIM_CHARDEV_SOURCE_TYPE_PIPE: + DUP_FIELD(t, s, source_dev.pipe.path); + break; + case CIM_CHARDEV_SOURCE_TYPE_UNIXSOCK: + DUP_FIELD(t, s, source_dev.unixsock.path); + DUP_FIELD(t, s, source_dev.unixsock.mode); + break; + case CIM_CHARDEV_SOURCE_TYPE_UDP: + DUP_FIELD(t, s, source_dev.udp.bind_host); + DUP_FIELD(t, s, source_dev.udp.bind_service); + DUP_FIELD(t, s, source_dev.udp.connect_host); + DUP_FIELD(t, s, source_dev.udp.connect_service); + break; + case CIM_CHARDEV_SOURCE_TYPE_TCP: + DUP_FIELD(t, s, source_dev.tcp.mode); + DUP_FIELD(t, s, source_dev.tcp.protocol); + DUP_FIELD(t, s, source_dev.tcp.host); + DUP_FIELD(t, s, source_dev.tcp.service); + break; + default: + /* Nothing to do for : + CIM_CHARDEV_SOURCE_TYPE_STDIO + CIM_CHARDEV_SOURCE_TYPE_NULL + CIM_CHARDEV_SOURCE_TYPE_VC + CIM_CHARDEV_SOURCE_TYPE_SPICEVMC + */ + break; + } +} + static void cleanup_input_device(struct input_device *dev) { if (dev == NULL) @@ -157,6 +301,8 @@ void cleanup_virt_device(struct virt_device *dev) cleanup_graphics_device(&dev->dev.graphics); else if (dev->type == CIM_RES_TYPE_INPUT) cleanup_input_device(&dev->dev.input); + else if (dev->type == CIM_RES_TYPE_CONSOLE) + cleanup_console_device(&dev->dev.console);
free(dev->id);
@@ -613,6 +759,140 @@ static char *get_attr_value_default(xmlNode *node, char *attrname, return ret; }
+static int parse_console_device(xmlNode *node, struct virt_device **vdevs) +{ + struct virt_device *vdev = NULL; + struct console_device *cdev = NULL; + char *source_type_str = NULL; + char *target_port_ID = NULL; + char *udp_source_mode = NULL; + + xmlNode *child = NULL; + + vdev = calloc(1, sizeof(*vdev)); + if (vdev == NULL) + goto err; + + cdev = &(vdev->dev.console); + + source_type_str = get_attr_value(node, "type"); + if (source_type_str == NULL) + goto err; + CU_DEBUG("console device type = %s", source_type_str); + + cdev->source_type = chardev_source_type_StrToID(source_type_str); + if (cdev->source_type == CIM_CHARDEV_SOURCE_TYPE_UNKNOWN) + goto err; + + CU_DEBUG("console device type ID = %d", cdev->source_type); + free(source_type_str);
This is free()'d again in err:, so we get a Coverity complaint about a double free. You need a "source_type_str = NULL;" here.
+ + for (child = node->children; child != NULL; child = child->next) { + if (XSTREQ(child->name, "target")) { + cdev->target_type = get_attr_value(child, "type"); + CU_DEBUG("Console device target type = '%s'", + cdev->target_type);
If get_attr_value() returns NULL in cdev->target_type, then your CU_DEBUG() isn't going to be happy.
+ target_port_ID = get_attr_value(child, "port"); + if (target_port_ID == NULL) + goto err; + } + + if (XSTREQ(child->name, "source")) { + switch (cdev->source_type) + { + case CIM_CHARDEV_SOURCE_TYPE_PTY: + cdev->source_dev.pty.path = + get_attr_value(child, "path"); + break; + case CIM_CHARDEV_SOURCE_TYPE_DEV: + cdev->source_dev.dev.path = + get_attr_value(child, "path"); + break; + case CIM_CHARDEV_SOURCE_TYPE_FILE: + cdev->source_dev.file.path = + get_attr_value(child, "path"); + break; + case CIM_CHARDEV_SOURCE_TYPE_PIPE: + cdev->source_dev.pipe.path = + get_attr_value(child, "path"); + break; + case CIM_CHARDEV_SOURCE_TYPE_UNIXSOCK: + cdev->source_dev.unixsock.mode = + get_attr_value(child, "mode"); + cdev->source_dev.unixsock.path = + get_attr_value(child, "path"); + break; + case CIM_CHARDEV_SOURCE_TYPE_UDP: + udp_source_mode = get_attr_value(child, "mode"); + if (udp_source_mode == NULL) + goto err; + if (STREQC(udp_source_mode, "bind")) { + cdev->source_dev.udp.bind_host = + get_attr_value(child, "host"); + cdev->source_dev.udp.bind_service = + get_attr_value(child, "service"); + } + else if (STREQC(udp_source_mode, "connect")) { + cdev->source_dev.udp.connect_host = + get_attr_value(child, "host"); + cdev->source_dev.udp.connect_service = + get_attr_value(child, "service"); + } + else { + CU_DEBUG("unknown udp mode: %s", + udp_source_mode); + goto err; + } + free(udp_source_mode);
This is free()'d again in err:, so we get a Coverity complaint about a double free. You'll need a udp_source_mode = NULL; here.
+ break; + case CIM_CHARDEV_SOURCE_TYPE_TCP: + cdev->source_dev.tcp.mode = + get_attr_value(child, "mode"); + cdev->source_dev.tcp.host = + get_attr_value(child, "host"); + cdev->source_dev.tcp.service = + get_attr_value(child, "service"); + break; + + default: + /* Nothing to do for : + CIM_CHARDEV_SOURCE_TYPE_STDIO + CIM_CHARDEV_SOURCE_TYPE_NULL + CIM_CHARDEV_SOURCE_TYPE_VC + CIM_CHARDEV_SOURCE_TYPE_SPICEVMC + */ + break; + } + }
Not a whole lot of NULL error checking in any of the get_attr_value() calls, but that seems to be par for the course in the libvirt-cim code. The rest seemed fine to me. I can squash in the above listed changes before pushing unless you really want to make a v2. John
+ if ((cdev->source_type == CIM_CHARDEV_SOURCE_TYPE_TCP) + && XSTREQ(child->name, "protocol")) { + cdev->source_dev.tcp.protocol = + get_attr_value(child, "type"); + } + } + + vdev->type = CIM_RES_TYPE_CONSOLE; + + if (-1 == asprintf(&vdev->id, "charconsole:%s", target_port_ID)) { + CU_DEBUG("Failed to create charconsole id string"); + goto err; + } + + *vdevs = vdev; + free(target_port_ID); + + return 1; + + err: + free(source_type_str); + free(target_port_ID); + free(udp_source_mode); + cleanup_console_device(cdev); + free(vdev); + + return 0; +} + static int parse_graphics_device(xmlNode *node, struct virt_device **vdevs) { struct virt_device *vdev = NULL; @@ -664,8 +944,20 @@ static int parse_graphics_device(xmlNode *node, struct virt_device **vdevs) child = child->next) { if (XSTREQ(child->name, "source")) gdev->dev.vnc.host = get_attr_value(child, "path"); - else if (XSTREQ(child->name, "target")) - gdev->dev.vnc.port = get_attr_value(child, "port"); + else if (XSTREQ(child->name, "target")) { + gdev->dev.vnc.port = + get_attr_value(child, "port"); + /* The graphics pty console can only be a + virtio console. If 'type' is not set in the + xml, the default of libvirt is virtio.*/ + char *t_type = get_attr_value(child, "type"); + if (t_type != NULL && !STREQC(t_type, "virtio")) { + CU_DEBUG("Not a pty-virtio graphics console"); + free(t_type); + goto err; + } + free(t_type); + } } } else { @@ -841,6 +1133,11 @@ static int parse_devices(const char *xml, struct virt_device **_list, int type) func = &parse_graphics_device; break;
+ case CIM_RES_TYPE_CONSOLE: + xpathstr = CONSOLE_XPATH; + func = &parse_console_device; + break; + case CIM_RES_TYPE_INPUT: xpathstr = INPUT_XPATH; func = &parse_input_device; @@ -876,11 +1173,6 @@ static int parse_devices(const char *xml, struct virt_device **_list, int type) return count; }
-#define DUP_FIELD(d, s, f) do { \ - if ((s)->f != NULL) \ - (d)->f = strdup((s)->f); \ - } while (0); - struct virt_device *virt_device_dup(struct virt_device *_dev) { struct virt_device *dev; @@ -939,8 +1231,10 @@ struct virt_device *virt_device_dup(struct virt_device *_dev) } else if (dev->type == CIM_RES_TYPE_INPUT) { DUP_FIELD(dev, _dev, dev.input.type); DUP_FIELD(dev, _dev, dev.input.bus); + } else if (dev->type == CIM_RES_TYPE_CONSOLE) { + console_device_dup(&dev->dev.console, + &_dev->dev.console); } - return dev; }
@@ -1299,6 +1593,9 @@ int get_dominfo_from_xml(const char *xml, struct domain **dominfo) (*dominfo)->dev_graphics_ct = parse_devices(xml, &(*dominfo)->dev_graphics, CIM_RES_TYPE_GRAPHICS); + (*dominfo)->dev_console_ct = parse_devices(xml, + &(*dominfo)->dev_console, + CIM_RES_TYPE_CONSOLE); (*dominfo)->dev_input_ct = parse_devices(xml, &(*dominfo)->dev_input, CIM_RES_TYPE_INPUT); @@ -1396,6 +1693,7 @@ void cleanup_dominfo(struct domain **dominfo) cleanup_virt_devices(&dom->dev_vcpu, dom->dev_vcpu_ct); cleanup_virt_devices(&dom->dev_graphics, dom->dev_graphics_ct); cleanup_virt_devices(&dom->dev_input, dom->dev_input_ct); + cleanup_virt_devices(&dom->dev_console, dom->dev_console_ct);
free(dom);
diff --git a/libxkutil/device_parsing.h b/libxkutil/device_parsing.h index 14e49b8..2803d6a 100644 --- a/libxkutil/device_parsing.h +++ b/libxkutil/device_parsing.h @@ -1,5 +1,5 @@ /* - * Copyright IBM Corp. 2007 + * Copyright IBM Corp. 2007, 2013 * * Authors: * Dan Smith <danms@us.ibm.com> @@ -111,6 +111,43 @@ struct graphics_device { } dev; };
+struct path_device { + char *path; +}; + +struct unixsock_device { + char *path; + char *mode; +}; + +struct tcp_device { + char *mode; + char *protocol; + char *host; + char *service; +}; + +struct udp_device { + char *bind_host; + char *bind_service; + char *connect_host; + char *connect_service; +}; + +struct console_device { + uint16_t source_type; + union { + struct path_device file; + struct path_device pty; + struct path_device dev; + struct path_device pipe; + struct unixsock_device unixsock; + struct tcp_device tcp; + struct udp_device udp; + } source_dev; + char *target_type; +}; + struct input_device { char *type; char *bus; @@ -125,6 +162,7 @@ struct virt_device { struct vcpu_device vcpu; struct emu_device emu; struct graphics_device graphics; + struct console_device console; struct input_device input; } dev; char *id; @@ -182,6 +220,9 @@ struct domain { struct virt_device *dev_graphics; int dev_graphics_ct;
+ struct virt_device *dev_console; + int dev_console_ct; + struct virt_device *dev_emu;
struct virt_device *dev_input; diff --git a/libxkutil/xmlgen.c b/libxkutil/xmlgen.c index 2ca2341..45bfb04 100644 --- a/libxkutil/xmlgen.c +++ b/libxkutil/xmlgen.c @@ -1,5 +1,5 @@ /* - * Copyright IBM Corp. 2007 + * Copyright IBM Corp. 2007, 2013 * * Authors: * Dan Smith <danms@us.ibm.com> @@ -42,6 +42,189 @@ typedef const char *(*devfn_t)(xmlNodePtr node, struct domain *dominfo); typedef const char *(*poolfn_t)(xmlNodePtr node, struct virt_pool *pool); typedef const char *(*resfn_t)(xmlNodePtr node, struct virt_pool_res *res);
+static int _count_graphics_console_definitions(struct domain *dominfo) +{ + int i; + int num = 0; + + for (i = 0; i < dominfo->dev_graphics_ct; i++) { + struct virt_device *_dev = &dominfo->dev_graphics[i]; + if (_dev->type == CIM_RES_TYPE_UNKNOWN) + continue; + + struct graphics_device *dev = &_dev->dev.graphics; + + if (STREQC(dev->type, "console")) { + num++; + } + } + CU_DEBUG("Found %d console defintions in graphics devices.",num); + return num; + +} + +static const char *console_xml(xmlNodePtr root, struct domain *dominfo) +{ + int i; + xmlNodePtr console; + xmlNodePtr tmp; + int num_graphics_consol_def = 0; + int num_suppressed_console_def = 0; + + num_graphics_consol_def = _count_graphics_console_definitions(dominfo); + + for (i = 0; i < dominfo->dev_console_ct; i++) { + struct virt_device *_dev = &dominfo->dev_console[i]; + if (_dev->type == CIM_RES_TYPE_UNKNOWN) + continue; + + struct console_device *cdev = &_dev->dev.console; + + /* Due to backward compatibility, the graphics device handling + is still parsing consoles: + source = pty, target = virtio (which is the default target) + But the console device handling processes these kind of + consoles too. This would lead to a duplication of these + default consoles in the domain xml definition. + This code prevents the console handling of writing xml for + duplicate pty/virtio consoles which are written by the + graphics device handling. */ + if (cdev->source_type == CIM_CHARDEV_SOURCE_TYPE_PTY && + (cdev->target_type == NULL || + STREQC(cdev->target_type, "virtio"))) { + if (num_suppressed_console_def < + num_graphics_consol_def) { + num_suppressed_console_def++; + continue; + } + } + + console = xmlNewChild(root, NULL, BAD_CAST "console", NULL); + if (console == NULL) + return XML_ERROR; + + xmlNewProp(console, BAD_CAST "type", + BAD_CAST + chardev_source_type_IDToStr(cdev->source_type)); + + switch (cdev->source_type) { + case CIM_CHARDEV_SOURCE_TYPE_PTY: + /* The path property is not mandatory */ + if (cdev->source_dev.pty.path) { + tmp = xmlNewChild(console, NULL, + BAD_CAST "source", NULL); + if (tmp == NULL) + return XML_ERROR; + xmlNewProp(tmp, BAD_CAST "path", + BAD_CAST cdev->source_dev.pty.path); + } + break; + case CIM_CHARDEV_SOURCE_TYPE_DEV: + tmp = xmlNewChild(console, NULL, + BAD_CAST "source", NULL); + if (tmp == NULL) + return XML_ERROR; + xmlNewProp(tmp, BAD_CAST "path", + BAD_CAST cdev->source_dev.dev.path); + break; + case CIM_CHARDEV_SOURCE_TYPE_FILE: + tmp = xmlNewChild(console, NULL, + BAD_CAST "source", NULL); + if (tmp == NULL) + return XML_ERROR; + xmlNewProp(tmp, BAD_CAST "path", + BAD_CAST cdev->source_dev.file.path); + break; + case CIM_CHARDEV_SOURCE_TYPE_PIPE: + tmp = xmlNewChild(console, NULL, + BAD_CAST "source", NULL); + if (tmp == NULL) + return XML_ERROR; + xmlNewProp(tmp, BAD_CAST "path", + BAD_CAST cdev->source_dev.pipe.path); + break; + case CIM_CHARDEV_SOURCE_TYPE_UNIXSOCK: + tmp = xmlNewChild(console, NULL, + BAD_CAST "source", NULL); + if (tmp == NULL) + return XML_ERROR; + xmlNewProp(tmp, BAD_CAST "mode", + BAD_CAST cdev->source_dev.unixsock.mode); + xmlNewProp(tmp, BAD_CAST "path", + BAD_CAST cdev->source_dev.unixsock.path); + break; + case CIM_CHARDEV_SOURCE_TYPE_UDP: + tmp = xmlNewChild(console, NULL, + BAD_CAST "source", NULL); + if (tmp == NULL) + return XML_ERROR; + xmlNewProp(tmp, BAD_CAST "mode", BAD_CAST "bind"); + xmlNewProp(tmp, BAD_CAST "host", + BAD_CAST cdev->source_dev.udp.bind_host); + /* The service property is not mandatory */ + if (cdev->source_dev.udp.bind_service) + xmlNewProp(tmp, BAD_CAST "service", + BAD_CAST + cdev->source_dev.udp.bind_service); + + tmp = xmlNewChild(console, NULL, + BAD_CAST "source", NULL); + if (tmp == NULL) + return XML_ERROR; + xmlNewProp(tmp, BAD_CAST "mode", BAD_CAST "connect"); + xmlNewProp(tmp, BAD_CAST "host", + BAD_CAST cdev->source_dev.udp.connect_host); + /* The service property is not mandatory */ + if (cdev->source_dev.udp.connect_service) + xmlNewProp(tmp, BAD_CAST "service", + BAD_CAST + cdev->source_dev.udp.connect_service); + + break; + case CIM_CHARDEV_SOURCE_TYPE_TCP: + tmp = xmlNewChild(console, NULL, + BAD_CAST "source", NULL); + if (tmp == NULL) + return XML_ERROR; + xmlNewProp(tmp, BAD_CAST "mode", + BAD_CAST cdev->source_dev.tcp.mode); + xmlNewProp(tmp, BAD_CAST "host", + BAD_CAST cdev->source_dev.tcp.host); + if (cdev->source_dev.tcp.service) + xmlNewProp(tmp, BAD_CAST "service", + BAD_CAST + cdev->source_dev.tcp.service); + if (cdev->source_dev.tcp.protocol) { + tmp = xmlNewChild(console, NULL, + BAD_CAST "protocol", NULL); + if (tmp == NULL) + return XML_ERROR; + xmlNewProp(tmp, BAD_CAST "type", + BAD_CAST cdev->source_dev.tcp.protocol); + } + break; + default: + /* Nothing to do for : + CIM_CHARDEV_SOURCE_TYPE_STDIO + CIM_CHARDEV_SOURCE_TYPE_NULL + CIM_CHARDEV_SOURCE_TYPE_VC + CIM_CHARDEV_SOURCE_TYPE_SPICEVMC + */ + break; + } + + if (cdev->target_type) { + tmp = xmlNewChild(console, NULL, + BAD_CAST "target", NULL); + if (tmp == NULL) + return XML_ERROR; + xmlNewProp(tmp, BAD_CAST "type", + BAD_CAST cdev->target_type); + } + } + return NULL; +} + static char *disk_block_xml(xmlNodePtr root, struct disk_device *dev) { xmlNodePtr disk; @@ -977,6 +1160,11 @@ char *device_to_xml(struct virt_device *_dev) dominfo->dev_graphics_ct = 1; dominfo->dev_graphics = dev; break; + case CIM_RES_TYPE_CONSOLE: + func = console_xml; + dominfo->dev_console_ct = 1; + dominfo->dev_console = dev; + break; case CIM_RES_TYPE_INPUT: func = input_xml; dominfo->dev_input_ct = 1; @@ -1017,6 +1205,7 @@ char *system_to_xml(struct domain *dominfo) &disk_xml, &net_xml, &input_xml, + &console_xml, &graphics_xml, &emu_xml, NULL diff --git a/src/svpc_types.h b/src/svpc_types.h index 2e4d73f..0f46a86 100644 --- a/src/svpc_types.h +++ b/src/svpc_types.h @@ -25,6 +25,7 @@ #define CIM_OPERATIONAL_STATUS 2
#define CIM_RES_TYPE_ALL 0 +#define CIM_RES_TYPE_OTHER 1 #define CIM_RES_TYPE_PROC 3 #define CIM_RES_TYPE_MEM 4 #define CIM_RES_TYPE_NET 10 @@ -34,8 +35,9 @@ #define CIM_RES_TYPE_INPUT 13 #define CIM_RES_TYPE_UNKNOWN 1000 #define CIM_RES_TYPE_IMAGE 32768 +#define CIM_RES_TYPE_CONSOLE 32769
-#define CIM_RES_TYPE_COUNT 6 +#define CIM_RES_TYPE_COUNT 7 const static int cim_res_types[CIM_RES_TYPE_COUNT] = {CIM_RES_TYPE_NET, CIM_RES_TYPE_DISK, @@ -43,6 +45,7 @@ const static int cim_res_types[CIM_RES_TYPE_COUNT] = CIM_RES_TYPE_PROC, CIM_RES_TYPE_GRAPHICS, CIM_RES_TYPE_INPUT, + CIM_RES_TYPE_CONSOLE, };
#define CIM_VSSD_RECOVERY_NONE 2

On 09/10/2013 10:38 PM, John Ferlan wrote: [...]
+ + CU_DEBUG("console device type ID = %d", cdev->source_type); + free(source_type_str);
This is free()'d again in err:, so we get a Coverity complaint about a double free. You need a "source_type_str = NULL;" here. oops ... will fix by moving to the end
+ + for (child = node->children; child != NULL; child = child->next) { + if (XSTREQ(child->name, "target")) { + cdev->target_type = get_attr_value(child, "type"); + CU_DEBUG("Console device target type = '%s'", + cdev->target_type);
If get_attr_value() returns NULL in cdev->target_type, then your CU_DEBUG() isn't going to be happy. actually, I expect CU_DEBUG to handle that gracefully... as it does in other places (see parse_graphics_device, vnc port determination)
[...]
+ } + free(udp_source_mode);
This is free()'d again in err:, so we get a Coverity complaint about a double free. You'll need a udp_source_mode = NULL; here. yep
+ break; + case CIM_CHARDEV_SOURCE_TYPE_TCP: + cdev->source_dev.tcp.mode = + get_attr_value(child, "mode"); + cdev->source_dev.tcp.host = + get_attr_value(child, "host"); + cdev->source_dev.tcp.service = + get_attr_value(child, "service"); + break; + + default: + /* Nothing to do for : + CIM_CHARDEV_SOURCE_TYPE_STDIO + CIM_CHARDEV_SOURCE_TYPE_NULL + CIM_CHARDEV_SOURCE_TYPE_VC + CIM_CHARDEV_SOURCE_TYPE_SPICEVMC + */ + break; + } + }
Not a whole lot of NULL error checking in any of the get_attr_value() calls, but that seems to be par for the course in the libvirt-cim code. at some point in time we should consider a 'spring clean'
The rest seemed fine to me. I can squash in the above listed changes before pushing unless you really want to make a v2. I'll make a v2, as I saw some other nits, like [...]
+ if (-1 == asprintf(&vdev->id, "charconsole:%s", target_port_ID)) { (left hand side constant in comparison) which escaped my attention before ... + CU_DEBUG("Failed to create charconsole id string"); + goto err; + }
-- Mit freundlichen Grüßen/Kind Regards Viktor Mihajlovski IBM Deutschland Research & Development GmbH Vorsitzender des Aufsichtsrats: Martina Köderitz Geschäftsführung: Dirk Wittkopp Sitz der Gesellschaft: Böblingen Registergericht: Amtsgericht Stuttgart, HRB 243294

From: Thilo Boehm <tboehm@linux.vnet.ibm.com> Instance support for console RASDs. The ResourceType of the returned instances is is '1' (Other) and the OtherResourceType is 'console'. Implemented CIM operations: enumerate instances enumerate instance names get instance Signed-off-by: Thilo Boehm <tboehm@linux.vnet.ibm.com> Signed-off-by: Viktor Mihajlovski <mihajlov@linux.vnet.ibm.com> Reviewed-by: Boris Fiuczynski <fiuczy@linux.vnet.ibm.com> --- src/Virt_RASD.c | 148 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 147 insertions(+), 1 deletion(-) diff --git a/src/Virt_RASD.c b/src/Virt_RASD.c index 150ccd3..7d72831 100644 --- a/src/Virt_RASD.c +++ b/src/Virt_RASD.c @@ -1,5 +1,5 @@ /* - * Copyright IBM Corp. 2007 + * Copyright IBM Corp. 2007, 2013 * * Authors: * Dan Smith <danms@us.ibm.com> @@ -662,6 +662,142 @@ static CMPIStatus set_graphics_rasd_params(const struct virt_device *dev, return s; } +static char* _build_console_url(const char *protocol, + const char *host, + const char *port) +{ + char* result = NULL; + + if (NULL == host) + goto out; + + if (STREQC("file", protocol)) { + /* The host string contains the file name. + Even if the file name does not start with a '/' + it is treated by libvirt as a full qualified path. + */ + if ('/' == host[0]) { + if (asprintf(&result, "file://%s", host) < 0) + result = NULL; + goto out; + } else { + if (asprintf(&result, "file:///%s", host) < 0) + result = NULL; + goto out; + } + } + /* The assumption is that the host does not contain a port. + If the host string contains a ':', + the host is treated as an IPv6 address. + */ + if (NULL == strchr(host, ':')) { + if (NULL == port) { + if (asprintf(&result,"%s://%s", protocol, host) < 0) + result = NULL; + goto out; + } else { + if (asprintf(&result,"%s://%s:%s", protocol, + host,port) < 0) + result = NULL; + goto out; + } + } + out: + return result; +} + + +static CMPIStatus set_console_rasd_params(const struct virt_device *vdev, + CMPIInstance *inst) +{ + CMPIStatus s = {CMPI_RC_OK, NULL}; + const struct console_device *cdev = NULL; + char* tmp = NULL; + + cdev = &vdev->dev.console; + + CMSetProperty(inst, "OtherResourceType", "console", CMPI_chars); + CMSetProperty(inst, "SourceType", + (CMPIValue *)&cdev->source_type, CMPI_uint16); + CMSetProperty(inst, "TargetType", + (CMPIValue *)cdev->target_type, CMPI_chars); + + switch (cdev->source_type) { + case CIM_CHARDEV_SOURCE_TYPE_PTY: + CMSetProperty(inst, "SourcePath", + (CMPIValue *)cdev->source_dev.pty.path, + CMPI_chars); + break; + case CIM_CHARDEV_SOURCE_TYPE_DEV: + CMSetProperty(inst, "SourcePath", + (CMPIValue *)cdev->source_dev.dev.path, + CMPI_chars); + break; + case CIM_CHARDEV_SOURCE_TYPE_FILE: + CMSetProperty(inst, "SourcePath", + (CMPIValue *)cdev->source_dev.file.path, + CMPI_chars); + break; + case CIM_CHARDEV_SOURCE_TYPE_PIPE: + CMSetProperty(inst, "SourcePath", + (CMPIValue *)cdev->source_dev.pipe.path, + CMPI_chars); + break; + case CIM_CHARDEV_SOURCE_TYPE_UNIXSOCK: + tmp = _build_console_url("file", + cdev->source_dev.unixsock.path, NULL); + if (STREQC(cdev->source_dev.unixsock.mode, "bind")) + CMSetProperty(inst, "BindURL", + (CMPIValue *)tmp, CMPI_chars); + + if (STREQC(cdev->source_dev.unixsock.mode, "connect")) + CMSetProperty(inst, "ConnectURL", + (CMPIValue *)tmp, CMPI_chars); + + free(tmp); + break; + case CIM_CHARDEV_SOURCE_TYPE_UDP: + tmp = _build_console_url("udp", + cdev->source_dev.udp.bind_host, + cdev->source_dev.udp.bind_service); + CMSetProperty(inst, "BindURL", + (CMPIValue *)tmp, CMPI_chars); + free(tmp); + + tmp = _build_console_url("udp", + cdev->source_dev.udp.connect_host, + cdev->source_dev.udp.connect_service); + CMSetProperty(inst, "ConnectURL", (CMPIValue *)tmp, CMPI_chars); + free(tmp); + break; + case CIM_CHARDEV_SOURCE_TYPE_TCP: + tmp = _build_console_url(cdev->source_dev.tcp.protocol, + cdev->source_dev.tcp.host, + cdev->source_dev.tcp.service); + if (STREQC(cdev->source_dev.tcp.mode, "bind")) + CMSetProperty(inst, "BindURL", + (CMPIValue *)tmp, CMPI_chars); + + if (STREQC(cdev->source_dev.tcp.mode, "connect")) + CMSetProperty(inst, "ConnectURL", + (CMPIValue *)tmp, CMPI_chars); + + free(tmp); + break; + + default: + /* Nothing to do for : + CIM_CHARDEV_SOURCE_TYPE_STDIO + CIM_CHARDEV_SOURCE_TYPE_NULL + CIM_CHARDEV_SOURCE_TYPE_VC + CIM_CHARDEV_SOURCE_TYPE_SPICEVMC + */ + break; + } + + return s; +} + static CMPIStatus set_input_rasd_params(const struct virt_device *dev, CMPIInstance *inst) { @@ -721,6 +857,9 @@ CMPIInstance *rasd_from_vdev(const CMPIBroker *broker, } else if (dev->type == CIM_RES_TYPE_GRAPHICS) { type = CIM_RES_TYPE_GRAPHICS; base = "GraphicsResourceAllocationSettingData"; + } else if (dev->type == CIM_RES_TYPE_CONSOLE) { + type = CIM_RES_TYPE_OTHER; + base = "ConsoleResourceAllocationSettingData"; } else if (dev->type == CIM_RES_TYPE_INPUT) { type = CIM_RES_TYPE_INPUT; base = "InputResourceAllocationSettingData"; @@ -777,6 +916,8 @@ CMPIInstance *rasd_from_vdev(const CMPIBroker *broker, s = set_graphics_rasd_params(dev, inst, host, CLASSNAME(ref)); } else if (dev->type == CIM_RES_TYPE_INPUT) { s = set_input_rasd_params(dev, inst); + } else if (dev->type == CIM_RES_TYPE_CONSOLE) { + s = set_console_rasd_params(dev, inst); } /* FIXME: Put the HostResource in place */ @@ -909,6 +1050,8 @@ CMPIrc res_type_from_rasd_classname(const char *cn, uint16_t *type) *type = CIM_RES_TYPE_INPUT; else if (STREQ(base, "StorageVolumeResourceAllocationSettingData")) *type = CIM_RES_TYPE_IMAGE; + else if (STREQ(base, "ConsoleResourceAllocationSettingData")) + *type = CIM_RES_TYPE_CONSOLE; else goto out; @@ -940,6 +1083,9 @@ CMPIrc rasd_classname_from_type(uint16_t type, const char **classname) case CIM_RES_TYPE_GRAPHICS: *classname = "GraphicsResourceAllocationSettingData"; break; + case CIM_RES_TYPE_CONSOLE: + *classname = "ConsoleResourceAllocationSettingData"; + break; case CIM_RES_TYPE_INPUT: *classname = "InputResourceAllocationSettingData"; break; -- 1.7.9.5

On 09/05/2013 11:36 AM, Viktor Mihajlovski wrote:
From: Thilo Boehm <tboehm@linux.vnet.ibm.com>
Instance support for console RASDs.
The ResourceType of the returned instances is is '1' (Other) and the OtherResourceType is 'console'.
Implemented CIM operations: enumerate instances enumerate instance names get instance
Signed-off-by: Thilo Boehm <tboehm@linux.vnet.ibm.com> Signed-off-by: Viktor Mihajlovski <mihajlov@linux.vnet.ibm.com> Reviewed-by: Boris Fiuczynski <fiuczy@linux.vnet.ibm.com> --- src/Virt_RASD.c | 148 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 147 insertions(+), 1 deletion(-)
diff --git a/src/Virt_RASD.c b/src/Virt_RASD.c index 150ccd3..7d72831 100644 --- a/src/Virt_RASD.c +++ b/src/Virt_RASD.c @@ -1,5 +1,5 @@ /* - * Copyright IBM Corp. 2007 + * Copyright IBM Corp. 2007, 2013 * * Authors: * Dan Smith <danms@us.ibm.com> @@ -662,6 +662,142 @@ static CMPIStatus set_graphics_rasd_params(const struct virt_device *dev, return s; }
+static char* _build_console_url(const char *protocol, + const char *host, + const char *port) +{ + char* result = NULL; + + if (NULL == host) + goto out; + + if (STREQC("file", protocol)) { + /* The host string contains the file name. + Even if the file name does not start with a '/' + it is treated by libvirt as a full qualified path. + */ + if ('/' == host[0]) { + if (asprintf(&result, "file://%s", host) < 0) + result = NULL; + goto out; + } else { + if (asprintf(&result, "file:///%s", host) < 0) + result = NULL; + goto out; + } + } + /* The assumption is that the host does not contain a port. + If the host string contains a ':', + the host is treated as an IPv6 address. + */ + if (NULL == strchr(host, ':')) { + if (NULL == port) { + if (asprintf(&result,"%s://%s", protocol, host) < 0) + result = NULL; + goto out; + } else { + if (asprintf(&result,"%s://%s:%s", protocol, + host,port) < 0) + result = NULL; + goto out; + } + } + out: + return result; +} + + +static CMPIStatus set_console_rasd_params(const struct virt_device *vdev, + CMPIInstance *inst) +{ + CMPIStatus s = {CMPI_RC_OK, NULL}; + const struct console_device *cdev = NULL; + char* tmp = NULL; + + cdev = &vdev->dev.console; + + CMSetProperty(inst, "OtherResourceType", "console", CMPI_chars); + CMSetProperty(inst, "SourceType", + (CMPIValue *)&cdev->source_type, CMPI_uint16); + CMSetProperty(inst, "TargetType", + (CMPIValue *)cdev->target_type, CMPI_chars); +
Since libxkutil/parse_console_device() didn't do any error checking w/r/t a NULL return on get_attr_value() calls, we could get into a lot of trouble here, but again par for the course in libvirt-cim!
+ switch (cdev->source_type) { + case CIM_CHARDEV_SOURCE_TYPE_PTY: + CMSetProperty(inst, "SourcePath", + (CMPIValue *)cdev->source_dev.pty.path, + CMPI_chars); + break; + case CIM_CHARDEV_SOURCE_TYPE_DEV: + CMSetProperty(inst, "SourcePath", + (CMPIValue *)cdev->source_dev.dev.path, + CMPI_chars); + break; + case CIM_CHARDEV_SOURCE_TYPE_FILE: + CMSetProperty(inst, "SourcePath", + (CMPIValue *)cdev->source_dev.file.path, + CMPI_chars); + break; + case CIM_CHARDEV_SOURCE_TYPE_PIPE: + CMSetProperty(inst, "SourcePath", + (CMPIValue *)cdev->source_dev.pipe.path, + CMPI_chars); + break; + case CIM_CHARDEV_SOURCE_TYPE_UNIXSOCK: + tmp = _build_console_url("file", + cdev->source_dev.unixsock.path, NULL); + if (STREQC(cdev->source_dev.unixsock.mode, "bind")) + CMSetProperty(inst, "BindURL", + (CMPIValue *)tmp, CMPI_chars); + + if (STREQC(cdev->source_dev.unixsock.mode, "connect")) + CMSetProperty(inst, "ConnectURL", + (CMPIValue *)tmp, CMPI_chars); + + free(tmp); + break; + case CIM_CHARDEV_SOURCE_TYPE_UDP: + tmp = _build_console_url("udp", + cdev->source_dev.udp.bind_host, + cdev->source_dev.udp.bind_service);
Since 'tmp' can be NULL, could there be any negative repercussion in the following?
+ CMSetProperty(inst, "BindURL", + (CMPIValue *)tmp, CMPI_chars); + free(tmp); + + tmp = _build_console_url("udp", + cdev->source_dev.udp.connect_host, + cdev->source_dev.udp.connect_service);
Same here
+ CMSetProperty(inst, "ConnectURL", (CMPIValue *)tmp, CMPI_chars); + free(tmp); + break; + case CIM_CHARDEV_SOURCE_TYPE_TCP: + tmp = _build_console_url(cdev->source_dev.tcp.protocol, + cdev->source_dev.tcp.host, + cdev->source_dev.tcp.service); + if (STREQC(cdev->source_dev.tcp.mode, "bind"))
Again
+ CMSetProperty(inst, "BindURL", + (CMPIValue *)tmp, CMPI_chars); + + if (STREQC(cdev->source_dev.tcp.mode, "connect"))
Again let me know if there's anything that needs to be done/checked and I can squash it in... John
+ CMSetProperty(inst, "ConnectURL", + (CMPIValue *)tmp, CMPI_chars); + + free(tmp); + break; + + default: + /* Nothing to do for : + CIM_CHARDEV_SOURCE_TYPE_STDIO + CIM_CHARDEV_SOURCE_TYPE_NULL + CIM_CHARDEV_SOURCE_TYPE_VC + CIM_CHARDEV_SOURCE_TYPE_SPICEVMC + */ + break; + } + + return s; +} + static CMPIStatus set_input_rasd_params(const struct virt_device *dev, CMPIInstance *inst) { @@ -721,6 +857,9 @@ CMPIInstance *rasd_from_vdev(const CMPIBroker *broker, } else if (dev->type == CIM_RES_TYPE_GRAPHICS) { type = CIM_RES_TYPE_GRAPHICS; base = "GraphicsResourceAllocationSettingData"; + } else if (dev->type == CIM_RES_TYPE_CONSOLE) { + type = CIM_RES_TYPE_OTHER; + base = "ConsoleResourceAllocationSettingData"; } else if (dev->type == CIM_RES_TYPE_INPUT) { type = CIM_RES_TYPE_INPUT; base = "InputResourceAllocationSettingData"; @@ -777,6 +916,8 @@ CMPIInstance *rasd_from_vdev(const CMPIBroker *broker, s = set_graphics_rasd_params(dev, inst, host, CLASSNAME(ref)); } else if (dev->type == CIM_RES_TYPE_INPUT) { s = set_input_rasd_params(dev, inst); + } else if (dev->type == CIM_RES_TYPE_CONSOLE) { + s = set_console_rasd_params(dev, inst); }
/* FIXME: Put the HostResource in place */ @@ -909,6 +1050,8 @@ CMPIrc res_type_from_rasd_classname(const char *cn, uint16_t *type) *type = CIM_RES_TYPE_INPUT; else if (STREQ(base, "StorageVolumeResourceAllocationSettingData")) *type = CIM_RES_TYPE_IMAGE; + else if (STREQ(base, "ConsoleResourceAllocationSettingData")) + *type = CIM_RES_TYPE_CONSOLE; else goto out;
@@ -940,6 +1083,9 @@ CMPIrc rasd_classname_from_type(uint16_t type, const char **classname) case CIM_RES_TYPE_GRAPHICS: *classname = "GraphicsResourceAllocationSettingData"; break; + case CIM_RES_TYPE_CONSOLE: + *classname = "ConsoleResourceAllocationSettingData"; + break; case CIM_RES_TYPE_INPUT: *classname = "InputResourceAllocationSettingData"; break;

On 09/10/2013 11:11 PM, John Ferlan wrote: [...]
+ CMSetProperty(inst, "TargetType", + (CMPIValue *)cdev->target_type, CMPI_chars); +
Since libxkutil/parse_console_device() didn't do any error checking w/r/t a NULL return on get_attr_value() calls, we could get into a lot of trouble here, but again par for the course in libvirt-cim!
+ switch (cdev->source_type) { + case CIM_CHARDEV_SOURCE_TYPE_PTY: + CMSetProperty(inst, "SourcePath", + (CMPIValue *)cdev->source_dev.pty.path, + CMPI_chars); + break; + case CIM_CHARDEV_SOURCE_TYPE_DEV: + CMSetProperty(inst, "SourcePath", + (CMPIValue *)cdev->source_dev.dev.path, + CMPI_chars); + break; + case CIM_CHARDEV_SOURCE_TYPE_FILE: + CMSetProperty(inst, "SourcePath", + (CMPIValue *)cdev->source_dev.file.path, + CMPI_chars); + break; + case CIM_CHARDEV_SOURCE_TYPE_PIPE: + CMSetProperty(inst, "SourcePath", + (CMPIValue *)cdev->source_dev.pipe.path, + CMPI_chars); + break; + case CIM_CHARDEV_SOURCE_TYPE_UNIXSOCK: + tmp = _build_console_url("file", + cdev->source_dev.unixsock.path, NULL); + if (STREQC(cdev->source_dev.unixsock.mode, "bind")) + CMSetProperty(inst, "BindURL", + (CMPIValue *)tmp, CMPI_chars); + + if (STREQC(cdev->source_dev.unixsock.mode, "connect")) + CMSetProperty(inst, "ConnectURL", + (CMPIValue *)tmp, CMPI_chars); + + free(tmp); + break; + case CIM_CHARDEV_SOURCE_TYPE_UDP: + tmp = _build_console_url("udp", + cdev->source_dev.udp.bind_host, + cdev->source_dev.udp.bind_service);
Since 'tmp' can be NULL, could there be any negative repercussion in the following? no, see above
+ CMSetProperty(inst, "BindURL", + (CMPIValue *)tmp, CMPI_chars); + free(tmp); + + tmp = _build_console_url("udp", + cdev->source_dev.udp.connect_host, + cdev->source_dev.udp.connect_service);
Same here
+ CMSetProperty(inst, "ConnectURL", (CMPIValue *)tmp, CMPI_chars); + free(tmp); + break; + case CIM_CHARDEV_SOURCE_TYPE_TCP: + tmp = _build_console_url(cdev->source_dev.tcp.protocol, + cdev->source_dev.tcp.host, + cdev->source_dev.tcp.service); + if (STREQC(cdev->source_dev.tcp.mode, "bind"))
Again
The CMPI interface allows you to explicitly set NULL string properties, so no trouble should arise from that at least (I have also checked the code in sfcb and Pegasus to be 100% sure). that is probably not good ... will fix in V2
+ CMSetProperty(inst, "BindURL", + (CMPIValue *)tmp, CMPI_chars); + + if (STREQC(cdev->source_dev.tcp.mode, "connect"))
Again
yep -- Mit freundlichen Grüßen/Kind Regards Viktor Mihajlovski IBM Deutschland Research & Development GmbH Vorsitzender des Aufsichtsrats: Martina Köderitz Geschäftsführung: Dirk Wittkopp Sitz der Gesellschaft: Böblingen Registergericht: Amtsgericht Stuttgart, HRB 243294

Extended the Virt_Device provider to return DisplayController devices for the consoles found. This mainly for the purpose of consistency with the other RASD types. Signed-off-by: Viktor Mihajlovski <mihajlov@linux.vnet.ibm.com> Reviewed-by: Boris Fiuczynski <fiuczy@linux.vnet.ibm.com> --- src/Virt_Device.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/Virt_Device.c b/src/Virt_Device.c index c3b515c..aa47276 100644 --- a/src/Virt_Device.c +++ b/src/Virt_Device.c @@ -251,6 +251,34 @@ static CMPIInstance *graphics_instance(const CMPIBroker *broker, return inst; } +static CMPIInstance *console_instance(const CMPIBroker *broker, + struct console_device *dev, + const virDomainPtr dom, + const char *ns) +{ + CMPIInstance *inst; + virConnectPtr conn; + const char *ctype; + + conn = virDomainGetConnect(dom); + inst = get_typed_instance(broker, + pfx_from_conn(conn), + "DisplayController", + ns, + true); + + if (inst == NULL) { + CU_DEBUG("Failed to get instance for DisplayController"); + return NULL; + } + + ctype = chardev_source_type_IDToStr(dev->source_type); + CMSetProperty(inst, "VideoProcessor", + (CMPIValue *)ctype, CMPI_chars); + + return inst; +} + int get_input_dev_caption(const char *type, const char *bus, char **cap) @@ -483,6 +511,11 @@ static bool device_instances(const CMPIBroker *broker, &dev->dev.graphics, dom, ns); + else if (dev->type == CIM_RES_TYPE_CONSOLE) + instance = console_instance(broker, + &dev->dev.console, + dom, + ns); else if (dev->type == CIM_RES_TYPE_INPUT) instance = input_instance(broker, &dev->dev.input, -- 1.7.9.5

On 09/05/2013 11:36 AM, Viktor Mihajlovski wrote:
Extended the Virt_Device provider to return DisplayController devices for the consoles found. This mainly for the purpose of consistency with the other RASD types.
Signed-off-by: Viktor Mihajlovski <mihajlov@linux.vnet.ibm.com> Reviewed-by: Boris Fiuczynski <fiuczy@linux.vnet.ibm.com> --- src/Virt_Device.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+)
ACK John

From: Thilo Boehm <tboehm@linux.vnet.ibm.com> An instance of KVM_ConsoleResourceAllocationSettingData can be added to domain specification for VSMS DefineSystem() to define a console for a domain. A console definition can not be modified or deleted. It only can be added at system definition and deleted at system deletion. If a KVM_ConsoleRASD is specified on a system definition, no default graphics adapter definition is done. Signed-off-by: Thilo Boehm <tboehm@linux.vnet.ibm.com> Signed-off-by: Viktor Mihajlovski <mihajlov@linux.vnet.ibm.com> Reviewed-by: Boris Fiuczynski <fiuczy@linux.vnet.ibm.com> --- src/Virt_VirtualSystemManagementService.c | 300 +++++++++++++++++++++++++++-- 1 file changed, 279 insertions(+), 21 deletions(-) diff --git a/src/Virt_VirtualSystemManagementService.c b/src/Virt_VirtualSystemManagementService.c index 6629b35..cd6ca9d 100644 --- a/src/Virt_VirtualSystemManagementService.c +++ b/src/Virt_VirtualSystemManagementService.c @@ -1,5 +1,5 @@ /* - * Copyright IBM Corp. 2007 + * Copyright IBM Corp. 2007, 2013 * * Authors: * Dan Smith <danms@us.ibm.com> @@ -626,7 +626,8 @@ static bool default_input_device(struct domain *domain) static bool add_default_devs(struct domain *domain) { - if (domain->dev_graphics_ct < 1) { + if (domain->dev_graphics_ct < 1 && + domain->dev_console_ct < 1) { if (!default_graphics_device(domain)) return false; } @@ -1339,47 +1340,284 @@ static int parse_sdl_address(const char *id, return ret; } -static int parse_vnc_address(const char *id, - char **ip, - char **port) +static int parse_ip_address(const char *id, + char **ip, + char **port) { int ret; char *tmp_ip = NULL; char *tmp_port = NULL; - CU_DEBUG("Entering parse_vnc_address, address is %s", id); + CU_DEBUG("Entering parse_ip_address, address is %s", id); if (strstr(id, "[") != NULL) { /* its an ipv6 address */ ret = sscanf(id, "%a[^]]]:%as", &tmp_ip, &tmp_port); + tmp_ip = realloc(tmp_ip, strlen(tmp_ip) + 2); strcat(tmp_ip, "]"); } else { ret = sscanf(id, "%a[^:]:%as", &tmp_ip, &tmp_port); } - if (ret != 2) { + /* ret == 2: address and port, ret == 1: address only */ + if (ret < 1) { ret = 0; goto out; } - if (ip) + if (ip) { *ip = strdup(tmp_ip); + CU_DEBUG("IP = '%s'",*ip); + } - if (port) + if (port && tmp_port) { *port = strdup(tmp_port); - - ret = 1; + CU_DEBUG("Port = '%s'",*port); + } out: - if (ip && port) - CU_DEBUG("Exiting parse_vnc_address, ip is %s, port is %s", - *ip, *port); - free(tmp_ip); free(tmp_port); return ret; } +static bool parse_console_url(const char *url, + char **protocol, + char **host, + char **port) +{ + bool success = false; + char *tmp_protocol = NULL; + char *tmp_address = NULL; + + CU_DEBUG("Entering parse_console_url:'%s'", url); + + if (sscanf(url,"%a[^:]://%as", &tmp_protocol, &tmp_address) != 2) + goto out; + + if (parse_ip_address(tmp_address, host, port) < 1) + goto out; + + if (protocol) { + *protocol = strdup(tmp_protocol); + CU_DEBUG("Protocol = '%s'", *protocol); + } + + success = true; + + out: + free(tmp_protocol); + free(tmp_address); + + return success; +} + +static const char *_unixsock_console_rasd_to_vdev(CMPIInstance *inst, + struct console_device *cdev) +{ + const char *val = NULL; + const char *val2 = NULL; + char* protocol = NULL; + + cdev->source_dev.unixsock.mode = NULL; + if (cu_get_str_prop(inst,"ConnectURL", &val) == CMPI_RC_OK) { + CU_DEBUG("ConnectURL = '%s'", val); + cdev->source_dev.unixsock.mode = strdup("connect"); + } + + if (cu_get_str_prop(inst, "BindURL", &val2) == CMPI_RC_OK) { + if (cdev->source_dev.unixsock.mode != NULL) + return "ConsoleRASD: Only ConnectURL or BindURL are allowed for " + "UNIX domain socket client/server."; + CU_DEBUG("BindURL = '%s'", val2); + cdev->source_dev.unixsock.mode = strdup("bind"); + val = val2; + } + + if (val) { + if (!parse_console_url(val, &protocol, &cdev->source_dev.unixsock.path, NULL)) + return "ConsoleRASD: Invalid ConnectURL or BindURL for " + "UNIX domain socket client/server."; + + if (!STREQC("file", protocol)) { + CU_DEBUG("Wrong ConsoleRASD protocol specified: '%s'",protocol); + free(protocol); + return "ConsoleRASD: Protocol 'file' was not specified for " + "ConnectURL or BindURL for UNIX domain socket client/server."; + } + free(protocol); + } else + return "ConsoleRASD: ConnectURL or BindURL not specified for " + "UNIX domain socket client/server."; + + return NULL; +} + +static const char *_udp_console_rasd_to_vdev(CMPIInstance *inst, + struct console_device *cdev) +{ + const char *val = NULL; + char* protocol = NULL; + + if (cu_get_str_prop(inst, "ConnectURL", &val) != CMPI_RC_OK) + return "ConsoleRASD: ConnectURL not specified for UDP network console."; + + if (!parse_console_url(val, &protocol, + &cdev->source_dev.udp.connect_host, + &cdev->source_dev.udp.connect_service)) + return "ConsoleRASD: Invalid ConnectURL specified for UDP network console."; + + if (!STREQC("udp" ,protocol)) { + CU_DEBUG("Wrong ConsoleRASD protocol specified: '%s'",protocol); + free(protocol); + return "ConsoleRASD: Protocol 'udp' was not specified at " + "ConnectURL for UDP network console."; + } + + free(protocol); + + if (cu_get_str_prop(inst, "BindURL", &val) != CMPI_RC_OK) + return "ConsoleRASD: BindURL not specified for UDP network console."; + + if (!parse_console_url(val,&protocol, + &cdev->source_dev.udp.bind_host, + &cdev->source_dev.udp.bind_service)) + return "ConsoleRASD: Invalid BindURL specified for UDP network console."; + + if (!STREQC("udp", protocol)) { + CU_DEBUG("Wrong ConsoleRASD protocol specified: '%s'",protocol); + free(protocol); + return "ConsoleRASD: Protocol 'udp' was not specified at BindURL " + "for UDP network console."; + } + + free(protocol); + return NULL; +} + +static const char *_tcp_console_rasd_to_vdev(CMPIInstance *inst, + struct console_device *cdev) +{ + const char *val = NULL; + const char *val2 = NULL; + + cdev->source_dev.tcp.mode = NULL; + if (cu_get_str_prop(inst, "ConnectURL", &val) == CMPI_RC_OK) { + CU_DEBUG("ConnectURL = '%s'",val); + cdev->source_dev.tcp.mode = strdup("connect"); + } + + if (cu_get_str_prop(inst, "BindURL", &val2) == CMPI_RC_OK) { + if (cdev->source_dev.tcp.mode != NULL) + return "ConsoleRASD: Only ConnectURL or BindURL are allowed for " + "TCP client/server console."; + CU_DEBUG("BindURL = '%s'",val2); + cdev->source_dev.tcp.mode = strdup("bind"); + val = val2; + } + + if (val) { + if (!parse_console_url(val, + &cdev->source_dev.tcp.protocol, + &cdev->source_dev.tcp.host, + &cdev->source_dev.tcp.service)) + return "ConsoleRASD: Invalid ConnectURL or BindURL for " + "TCP client/server console."; + if (cdev->source_dev.tcp.service == NULL) + return "ConsoleRASD: Missing TCP port for TCP client/server console."; + } else + return "ConsoleRASD: ConnectURL or BindURL not specified for " + "TCP client/server console."; + + if (STREQC("udp",cdev->source_dev.tcp.protocol)) { + CU_DEBUG("Wrong ConsoleRASD protocol specified: '%s'", cdev->source_dev.tcp.protocol); + return "ConsoleRASD: Invalid protocol 'udp' was specified at " + "TCP client/server console."; + } + + if (STREQC("file", cdev->source_dev.tcp.protocol)) { + CU_DEBUG("Wrong ConsoleRASD protocol specified: '%s'",cdev->source_dev.tcp.protocol); + return "ConsoleRASD: Invalid protocol 'file' was specified at " + "TCP client/server console."; + } + + return NULL; +} + +static const char *console_rasd_to_vdev(CMPIInstance *inst, + struct virt_device *dev) +{ + int rc = 0; + const char *msg = NULL; + const char *val = NULL; + struct console_device *cdev = &dev->dev.console; + uint16_t tmp; + + rc = cu_get_u16_prop(inst, "SourceType", &tmp); + if (rc != CMPI_RC_OK) + return "ConsoleRASD: SourceType field not specified."; + + if (tmp < 0 || tmp >= CIM_CHARDEV_SOURCE_TYPE_INVALIDTYPE) + return "ConsoleRASD: Invalid SourceType value"; + + cdev->source_type = tmp; + CU_DEBUG("Processeing SourceType: %d", cdev->source_type); + + /* property not required */ + if (cu_get_str_prop(inst, "TargetType", &val) == CMPI_RC_OK) + cdev->target_type = strdup(val); + CU_DEBUG("TargetType is '%s'", cdev->target_type); + + switch (cdev->source_type) { + case CIM_CHARDEV_SOURCE_TYPE_PTY: + /* property not required */ + if (cu_get_str_prop(inst, "SourcePath", &val) == CMPI_RC_OK) + cdev->source_dev.pty.path = strdup(val); + break; + case CIM_CHARDEV_SOURCE_TYPE_DEV: + if (cu_get_str_prop(inst, "SourcePath", &val) != CMPI_RC_OK) + return "ConsoleRASD: SourcePath not specified for Host device proxy."; + cdev->source_dev.dev.path = strdup(val); + break; + case CIM_CHARDEV_SOURCE_TYPE_FILE: + if (cu_get_str_prop(inst, "SourcePath", &val) != CMPI_RC_OK) + return "ConsoleRASD: SourcePath not specified for Device logfile."; + cdev->source_dev.file.path = strdup(val); + break; + case CIM_CHARDEV_SOURCE_TYPE_PIPE: + if (cu_get_str_prop(inst, "SourcePath", &val) != CMPI_RC_OK) + return "ConsoleRASD: SourcePath not specified for Named pipe."; + cdev->source_dev.pipe.path = strdup(val); + break; + case CIM_CHARDEV_SOURCE_TYPE_UNIXSOCK: + msg = _unixsock_console_rasd_to_vdev(inst, cdev); + if (msg != NULL) + return msg; + break; + case CIM_CHARDEV_SOURCE_TYPE_UDP: + msg = _udp_console_rasd_to_vdev(inst, cdev); + if (msg != NULL) + return msg; + break; + case CIM_CHARDEV_SOURCE_TYPE_TCP: + msg = _tcp_console_rasd_to_vdev(inst, cdev); + if (msg != NULL) + return msg; + break; + + default: + /* Nothing to do for : + CIM_CHARDEV_SOURCE_TYPE_STDIO + CIM_CHARDEV_SOURCE_TYPE_NULL + CIM_CHARDEV_SOURCE_TYPE_VC + CIM_CHARDEV_SOURCE_TYPE_SPICEVMC + */ + break; + } + + return NULL; +} + static const char *graphics_rasd_to_vdev(CMPIInstance *inst, struct virt_device *dev) { @@ -1411,10 +1649,10 @@ static const char *graphics_rasd_to_vdev(CMPIInstance *inst, val = "127.0.0.1:-1"; } - ret = parse_vnc_address(val, + ret = parse_ip_address(val, &dev->dev.graphics.dev.vnc.host, &dev->dev.graphics.dev.vnc.port); - if (ret != 1) { + if (ret != 2) { msg = "GraphicsRASD field Address not valid"; goto out; } @@ -1540,6 +1778,8 @@ static const char *_sysvirt_rasd_to_vdev(CMPIInstance *inst, return proc_rasd_to_vdev(inst, dev); } else if (type == CIM_RES_TYPE_GRAPHICS) { return graphics_rasd_to_vdev(inst, dev); + } else if (type == CIM_RES_TYPE_CONSOLE) { + return console_rasd_to_vdev(inst, dev); } else if (type == CIM_RES_TYPE_INPUT) { return input_rasd_to_vdev(inst, dev); } @@ -1601,7 +1841,7 @@ static const char *rasd_to_vdev(CMPIInstance *inst, return msg; } -static char *add_device_nodup(struct virt_device *dev, +static const char *add_device_nodup(struct virt_device *dev, struct virt_device *list, int max, int *index) @@ -1663,6 +1903,9 @@ static const char *classify_resources(CMPIArray *resources, if (!make_space(&domain->dev_graphics, domain->dev_graphics_ct, count)) return "Failed to alloc graphics list"; + if (!make_space(&domain->dev_console, domain->dev_console_ct, count)) + return "Failed to alloc console list"; + if (!make_space(&domain->dev_input, domain->dev_input_ct, count)) return "Failed to alloc input list"; @@ -1765,6 +2008,14 @@ static const char *classify_resources(CMPIArray *resources, domain->dev_graphics, gcount, &domain->dev_graphics_ct); + } else if (type == CIM_RES_TYPE_CONSOLE) { + msg = rasd_to_vdev(inst, + domain, + &domain->dev_console[domain->dev_console_ct], + ns, + p_error); + if (msg == NULL) + domain->dev_console_ct+=1; } else if (type == CIM_RES_TYPE_INPUT) { domain->dev_input_ct = 1; msg = rasd_to_vdev(inst, @@ -2570,6 +2821,9 @@ static struct virt_device **find_list(struct domain *dominfo, } else if (type == CIM_RES_TYPE_GRAPHICS) { list = &dominfo->dev_graphics; *count = &dominfo->dev_graphics_ct; + } else if (type == CIM_RES_TYPE_CONSOLE) { + list = &dominfo->dev_console; + *count = &dominfo->dev_console_ct; } else if (type == CIM_RES_TYPE_INPUT) { list = &dominfo->dev_input; *count = &dominfo->dev_input_ct; @@ -2693,7 +2947,8 @@ static CMPIStatus resource_del(struct domain *dominfo, if (STREQ(dev->id, devid)) { if ((type == CIM_RES_TYPE_GRAPHICS) || - (type == CIM_RES_TYPE_INPUT)) + (type == CIM_RES_TYPE_CONSOLE) || + (type == CIM_RES_TYPE_INPUT)) cu_statusf(_BROKER, &s, CMPI_RC_OK, ""); else { s = _resource_dynamic(dominfo, @@ -2774,7 +3029,9 @@ static CMPIStatus resource_add(struct domain *dominfo, goto out; } - if ((type == CIM_RES_TYPE_GRAPHICS) || (type == CIM_RES_TYPE_INPUT)) { + if ((type == CIM_RES_TYPE_GRAPHICS) || + (type == CIM_RES_TYPE_INPUT) || + (type == CIM_RES_TYPE_CONSOLE)) { (*count)++; cu_statusf(_BROKER, &s, CMPI_RC_OK, ""); goto out; @@ -2850,7 +3107,8 @@ static CMPIStatus resource_mod(struct domain *dominfo, } if ((type == CIM_RES_TYPE_GRAPHICS) || - (type == CIM_RES_TYPE_INPUT)) + (type == CIM_RES_TYPE_INPUT) || + (type == CIM_RES_TYPE_CONSOLE)) cu_statusf(_BROKER, &s, CMPI_RC_OK, ""); else { #if LIBVIR_VERSION_NUMBER < 9000 -- 1.7.9.5

On 09/05/2013 11:36 AM, Viktor Mihajlovski wrote:
From: Thilo Boehm <tboehm@linux.vnet.ibm.com>
An instance of KVM_ConsoleResourceAllocationSettingData can be added to domain specification for VSMS DefineSystem() to define a console for a domain. A console definition can not be modified or deleted. It only can be added at system definition and deleted at system deletion. If a KVM_ConsoleRASD is specified on a system definition, no default graphics adapter definition is done.
Signed-off-by: Thilo Boehm <tboehm@linux.vnet.ibm.com> Signed-off-by: Viktor Mihajlovski <mihajlov@linux.vnet.ibm.com> Reviewed-by: Boris Fiuczynski <fiuczy@linux.vnet.ibm.com> --- src/Virt_VirtualSystemManagementService.c | 300 +++++++++++++++++++++++++++-- 1 file changed, 279 insertions(+), 21 deletions(-)
diff --git a/src/Virt_VirtualSystemManagementService.c b/src/Virt_VirtualSystemManagementService.c index 6629b35..cd6ca9d 100644 --- a/src/Virt_VirtualSystemManagementService.c +++ b/src/Virt_VirtualSystemManagementService.c @@ -1,5 +1,5 @@ /* - * Copyright IBM Corp. 2007 + * Copyright IBM Corp. 2007, 2013 * * Authors: * Dan Smith <danms@us.ibm.com> @@ -626,7 +626,8 @@ static bool default_input_device(struct domain *domain)
static bool add_default_devs(struct domain *domain) { - if (domain->dev_graphics_ct < 1) { + if (domain->dev_graphics_ct < 1 && + domain->dev_console_ct < 1) { if (!default_graphics_device(domain)) return false; } @@ -1339,47 +1340,284 @@ static int parse_sdl_address(const char *id, return ret; }
-static int parse_vnc_address(const char *id, - char **ip, - char **port) +static int parse_ip_address(const char *id, + char **ip, + char **port) { int ret; char *tmp_ip = NULL; char *tmp_port = NULL;
- CU_DEBUG("Entering parse_vnc_address, address is %s", id); + CU_DEBUG("Entering parse_ip_address, address is %s", id); if (strstr(id, "[") != NULL) { /* its an ipv6 address */ ret = sscanf(id, "%a[^]]]:%as", &tmp_ip, &tmp_port); + tmp_ip = realloc(tmp_ip, strlen(tmp_ip) + 2);
What if tmp_ip == NULL? This one needs to be checked...
strcat(tmp_ip, "]"); } else { ret = sscanf(id, "%a[^:]:%as", &tmp_ip, &tmp_port); }
- if (ret != 2) { + /* ret == 2: address and port, ret == 1: address only */ + if (ret < 1) { ret = 0; goto out; }
- if (ip) + if (ip) { *ip = strdup(tmp_ip); + CU_DEBUG("IP = '%s'",*ip);
strdup() could return NULL, although I suppose it's only important for debugging...
+ }
- if (port) + if (port && tmp_port) { *port = strdup(tmp_port); - - ret = 1; + CU_DEBUG("Port = '%s'",*port);
Again - strdup() could return NULL
+ }
out: - if (ip && port) - CU_DEBUG("Exiting parse_vnc_address, ip is %s, port is %s", - *ip, *port); - free(tmp_ip); free(tmp_port);
return ret; }
+static bool parse_console_url(const char *url, + char **protocol, + char **host, + char **port) +{ + bool success = false; + char *tmp_protocol = NULL; + char *tmp_address = NULL; + + CU_DEBUG("Entering parse_console_url:'%s'", url); + + if (sscanf(url,"%a[^:]://%as", &tmp_protocol, &tmp_address) != 2) + goto out; + + if (parse_ip_address(tmp_address, host, port) < 1) + goto out; + + if (protocol) { + *protocol = strdup(tmp_protocol); + CU_DEBUG("Protocol = '%s'", *protocol);
strdup() failure again
+ } + + success = true; + + out: + free(tmp_protocol); + free(tmp_address); + + return success; +} + +static const char *_unixsock_console_rasd_to_vdev(CMPIInstance *inst, + struct console_device *cdev) +{ + const char *val = NULL; + const char *val2 = NULL; + char* protocol = NULL; + + cdev->source_dev.unixsock.mode = NULL; + if (cu_get_str_prop(inst,"ConnectURL", &val) == CMPI_RC_OK) { + CU_DEBUG("ConnectURL = '%s'", val); + cdev->source_dev.unixsock.mode = strdup("connect"); + } + + if (cu_get_str_prop(inst, "BindURL", &val2) == CMPI_RC_OK) { + if (cdev->source_dev.unixsock.mode != NULL) + return "ConsoleRASD: Only ConnectURL or BindURL are allowed for " + "UNIX domain socket client/server.";
Not quite sure I understand the above check - are you checking that both Connect and Bind aren't being used? Then perhaps the message should state - cannot supply both ConnectURL and BindURL. Of course the above strdup() could fail, but that's a different issue...
+ CU_DEBUG("BindURL = '%s'", val2); + cdev->source_dev.unixsock.mode = strdup("bind"); + val = val2; + } + + if (val) { + if (!parse_console_url(val, &protocol, &cdev->source_dev.unixsock.path, NULL)) + return "ConsoleRASD: Invalid ConnectURL or BindURL for " + "UNIX domain socket client/server."; + + if (!STREQC("file", protocol)) { + CU_DEBUG("Wrong ConsoleRASD protocol specified: '%s'",protocol); + free(protocol); + return "ConsoleRASD: Protocol 'file' was not specified for " + "ConnectURL or BindURL for UNIX domain socket client/server."; + } + free(protocol); + } else
Prefer to see "} else {" as it's cleaner and no one mistakenly adds a line eventually. BTW: We could get here if strdup() fails...
+ return "ConsoleRASD: ConnectURL or BindURL not specified for " + "UNIX domain socket client/server."; + + return NULL; +} + +static const char *_udp_console_rasd_to_vdev(CMPIInstance *inst, + struct console_device *cdev) +{ + const char *val = NULL; + char* protocol = NULL; + + if (cu_get_str_prop(inst, "ConnectURL", &val) != CMPI_RC_OK) + return "ConsoleRASD: ConnectURL not specified for UDP network console."; + + if (!parse_console_url(val, &protocol, + &cdev->source_dev.udp.connect_host, + &cdev->source_dev.udp.connect_service)) + return "ConsoleRASD: Invalid ConnectURL specified for UDP network console."; + + if (!STREQC("udp" ,protocol)) { + CU_DEBUG("Wrong ConsoleRASD protocol specified: '%s'",protocol); + free(protocol); + return "ConsoleRASD: Protocol 'udp' was not specified at " + "ConnectURL for UDP network console."; + } + + free(protocol); + + if (cu_get_str_prop(inst, "BindURL", &val) != CMPI_RC_OK) + return "ConsoleRASD: BindURL not specified for UDP network console."; + + if (!parse_console_url(val,&protocol, + &cdev->source_dev.udp.bind_host, + &cdev->source_dev.udp.bind_service)) + return "ConsoleRASD: Invalid BindURL specified for UDP network console."; + + if (!STREQC("udp", protocol)) { + CU_DEBUG("Wrong ConsoleRASD protocol specified: '%s'",protocol); + free(protocol); + return "ConsoleRASD: Protocol 'udp' was not specified at BindURL " + "for UDP network console."; + } + + free(protocol); + return NULL; +} + +static const char *_tcp_console_rasd_to_vdev(CMPIInstance *inst, + struct console_device *cdev) +{ + const char *val = NULL; + const char *val2 = NULL; + + cdev->source_dev.tcp.mode = NULL; + if (cu_get_str_prop(inst, "ConnectURL", &val) == CMPI_RC_OK) { + CU_DEBUG("ConnectURL = '%s'",val); + cdev->source_dev.tcp.mode = strdup("connect"); + } + + if (cu_get_str_prop(inst, "BindURL", &val2) == CMPI_RC_OK) { + if (cdev->source_dev.tcp.mode != NULL) + return "ConsoleRASD: Only ConnectURL or BindURL are allowed for " + "TCP client/server console.";
Similar comment from above - cannot supply both.
+ CU_DEBUG("BindURL = '%s'",val2); + cdev->source_dev.tcp.mode = strdup("bind"); + val = val2; + } + + if (val) { + if (!parse_console_url(val, + &cdev->source_dev.tcp.protocol, + &cdev->source_dev.tcp.host, + &cdev->source_dev.tcp.service)) + return "ConsoleRASD: Invalid ConnectURL or BindURL for " + "TCP client/server console."; + if (cdev->source_dev.tcp.service == NULL) + return "ConsoleRASD: Missing TCP port for TCP client/server console."; + } else
Again the "} else {"
+ return "ConsoleRASD: ConnectURL or BindURL not specified for " + "TCP client/server console."; + + if (STREQC("udp",cdev->source_dev.tcp.protocol)) { + CU_DEBUG("Wrong ConsoleRASD protocol specified: '%s'", cdev->source_dev.tcp.protocol); + return "ConsoleRASD: Invalid protocol 'udp' was specified at " + "TCP client/server console."; + } + + if (STREQC("file", cdev->source_dev.tcp.protocol)) { + CU_DEBUG("Wrong ConsoleRASD protocol specified: '%s'",cdev->source_dev.tcp.protocol); + return "ConsoleRASD: Invalid protocol 'file' was specified at " + "TCP client/server console."; + } + + return NULL; +} + +static const char *console_rasd_to_vdev(CMPIInstance *inst, + struct virt_device *dev) +{ + int rc = 0; + const char *msg = NULL; + const char *val = NULL; + struct console_device *cdev = &dev->dev.console; + uint16_t tmp; + + rc = cu_get_u16_prop(inst, "SourceType", &tmp); + if (rc != CMPI_RC_OK) + return "ConsoleRASD: SourceType field not specified."; + + if (tmp < 0 || tmp >= CIM_CHARDEV_SOURCE_TYPE_INVALIDTYPE)
tmp is a uint16_t so a < 0 comparison is not possible.
+ return "ConsoleRASD: Invalid SourceType value"; + + cdev->source_type = tmp; + CU_DEBUG("Processeing SourceType: %d", cdev->source_type); + + /* property not required */ + if (cu_get_str_prop(inst, "TargetType", &val) == CMPI_RC_OK) + cdev->target_type = strdup(val); + CU_DEBUG("TargetType is '%s'", cdev->target_type);
More strdup/debug Nothing overly serious - let me know how you want to proceed especially with respect to realloc() failure and unsigned compare less than zero John
+ + switch (cdev->source_type) { + case CIM_CHARDEV_SOURCE_TYPE_PTY: + /* property not required */ + if (cu_get_str_prop(inst, "SourcePath", &val) == CMPI_RC_OK) + cdev->source_dev.pty.path = strdup(val); + break; + case CIM_CHARDEV_SOURCE_TYPE_DEV: + if (cu_get_str_prop(inst, "SourcePath", &val) != CMPI_RC_OK) + return "ConsoleRASD: SourcePath not specified for Host device proxy."; + cdev->source_dev.dev.path = strdup(val); + break; + case CIM_CHARDEV_SOURCE_TYPE_FILE: + if (cu_get_str_prop(inst, "SourcePath", &val) != CMPI_RC_OK) + return "ConsoleRASD: SourcePath not specified for Device logfile."; + cdev->source_dev.file.path = strdup(val); + break; + case CIM_CHARDEV_SOURCE_TYPE_PIPE: + if (cu_get_str_prop(inst, "SourcePath", &val) != CMPI_RC_OK) + return "ConsoleRASD: SourcePath not specified for Named pipe."; + cdev->source_dev.pipe.path = strdup(val); + break; + case CIM_CHARDEV_SOURCE_TYPE_UNIXSOCK: + msg = _unixsock_console_rasd_to_vdev(inst, cdev); + if (msg != NULL) + return msg; + break; + case CIM_CHARDEV_SOURCE_TYPE_UDP: + msg = _udp_console_rasd_to_vdev(inst, cdev); + if (msg != NULL) + return msg; + break; + case CIM_CHARDEV_SOURCE_TYPE_TCP: + msg = _tcp_console_rasd_to_vdev(inst, cdev); + if (msg != NULL) + return msg; + break; + + default: + /* Nothing to do for : + CIM_CHARDEV_SOURCE_TYPE_STDIO + CIM_CHARDEV_SOURCE_TYPE_NULL + CIM_CHARDEV_SOURCE_TYPE_VC + CIM_CHARDEV_SOURCE_TYPE_SPICEVMC + */ + break; + } + + return NULL; +} + static const char *graphics_rasd_to_vdev(CMPIInstance *inst, struct virt_device *dev) { @@ -1411,10 +1649,10 @@ static const char *graphics_rasd_to_vdev(CMPIInstance *inst, val = "127.0.0.1:-1"; }
- ret = parse_vnc_address(val, + ret = parse_ip_address(val, &dev->dev.graphics.dev.vnc.host, &dev->dev.graphics.dev.vnc.port); - if (ret != 1) { + if (ret != 2) { msg = "GraphicsRASD field Address not valid"; goto out; } @@ -1540,6 +1778,8 @@ static const char *_sysvirt_rasd_to_vdev(CMPIInstance *inst, return proc_rasd_to_vdev(inst, dev); } else if (type == CIM_RES_TYPE_GRAPHICS) { return graphics_rasd_to_vdev(inst, dev); + } else if (type == CIM_RES_TYPE_CONSOLE) { + return console_rasd_to_vdev(inst, dev); } else if (type == CIM_RES_TYPE_INPUT) { return input_rasd_to_vdev(inst, dev); } @@ -1601,7 +1841,7 @@ static const char *rasd_to_vdev(CMPIInstance *inst, return msg; }
-static char *add_device_nodup(struct virt_device *dev, +static const char *add_device_nodup(struct virt_device *dev, struct virt_device *list, int max, int *index) @@ -1663,6 +1903,9 @@ static const char *classify_resources(CMPIArray *resources, if (!make_space(&domain->dev_graphics, domain->dev_graphics_ct, count)) return "Failed to alloc graphics list";
+ if (!make_space(&domain->dev_console, domain->dev_console_ct, count)) + return "Failed to alloc console list"; + if (!make_space(&domain->dev_input, domain->dev_input_ct, count)) return "Failed to alloc input list";
@@ -1765,6 +2008,14 @@ static const char *classify_resources(CMPIArray *resources, domain->dev_graphics, gcount, &domain->dev_graphics_ct); + } else if (type == CIM_RES_TYPE_CONSOLE) { + msg = rasd_to_vdev(inst, + domain, + &domain->dev_console[domain->dev_console_ct], + ns, + p_error); + if (msg == NULL) + domain->dev_console_ct+=1; } else if (type == CIM_RES_TYPE_INPUT) { domain->dev_input_ct = 1; msg = rasd_to_vdev(inst, @@ -2570,6 +2821,9 @@ static struct virt_device **find_list(struct domain *dominfo, } else if (type == CIM_RES_TYPE_GRAPHICS) { list = &dominfo->dev_graphics; *count = &dominfo->dev_graphics_ct; + } else if (type == CIM_RES_TYPE_CONSOLE) { + list = &dominfo->dev_console; + *count = &dominfo->dev_console_ct; } else if (type == CIM_RES_TYPE_INPUT) { list = &dominfo->dev_input; *count = &dominfo->dev_input_ct; @@ -2693,7 +2947,8 @@ static CMPIStatus resource_del(struct domain *dominfo,
if (STREQ(dev->id, devid)) { if ((type == CIM_RES_TYPE_GRAPHICS) || - (type == CIM_RES_TYPE_INPUT)) + (type == CIM_RES_TYPE_CONSOLE) || + (type == CIM_RES_TYPE_INPUT)) cu_statusf(_BROKER, &s, CMPI_RC_OK, ""); else { s = _resource_dynamic(dominfo, @@ -2774,7 +3029,9 @@ static CMPIStatus resource_add(struct domain *dominfo, goto out; }
- if ((type == CIM_RES_TYPE_GRAPHICS) || (type == CIM_RES_TYPE_INPUT)) { + if ((type == CIM_RES_TYPE_GRAPHICS) || + (type == CIM_RES_TYPE_INPUT) || + (type == CIM_RES_TYPE_CONSOLE)) { (*count)++; cu_statusf(_BROKER, &s, CMPI_RC_OK, ""); goto out; @@ -2850,7 +3107,8 @@ static CMPIStatus resource_mod(struct domain *dominfo, }
if ((type == CIM_RES_TYPE_GRAPHICS) || - (type == CIM_RES_TYPE_INPUT)) + (type == CIM_RES_TYPE_INPUT) || + (type == CIM_RES_TYPE_CONSOLE)) cu_statusf(_BROKER, &s, CMPI_RC_OK, ""); else { #if LIBVIR_VERSION_NUMBER < 9000

On 09/11/2013 12:05 AM, John Ferlan wrote: [...]
if (strstr(id, "[") != NULL) { /* its an ipv6 address */ ret = sscanf(id, "%a[^]]]:%as", &tmp_ip, &tmp_port); + tmp_ip = realloc(tmp_ip, strlen(tmp_ip) + 2);
What if tmp_ip == NULL? This one needs to be checked...
yes ... this will become ugly ...
strcat(tmp_ip, "]"); } else { ret = sscanf(id, "%a[^:]:%as", &tmp_ip, &tmp_port); }
- if (ret != 2) { + /* ret == 2: address and port, ret == 1: address only */ + if (ret < 1) { ret = 0; goto out; }
- if (ip) + if (ip) { *ip = strdup(tmp_ip); + CU_DEBUG("IP = '%s'",*ip);
strdup() could return NULL, although I suppose it's only important for debugging... I was prepared to contradict here ... but I am changing my mind while I type, stupid me ... I will rework the previous patches wrt to this as well
+ }
- if (port) + if (port && tmp_port) { *port = strdup(tmp_port); - - ret = 1; + CU_DEBUG("Port = '%s'",*port);
Again - strdup() could return NULL
+ }
out: - if (ip && port) - CU_DEBUG("Exiting parse_vnc_address, ip is %s, port is %s", - *ip, *port); - free(tmp_ip); free(tmp_port);
return ret; }
+static bool parse_console_url(const char *url, + char **protocol, + char **host, + char **port) +{ + bool success = false; + char *tmp_protocol = NULL; + char *tmp_address = NULL; + + CU_DEBUG("Entering parse_console_url:'%s'", url); + + if (sscanf(url,"%a[^:]://%as", &tmp_protocol, &tmp_address) != 2) + goto out; + + if (parse_ip_address(tmp_address, host, port) < 1) + goto out; + + if (protocol) { + *protocol = strdup(tmp_protocol); + CU_DEBUG("Protocol = '%s'", *protocol);
strdup() failure again
+ } + + success = true; + + out: + free(tmp_protocol); + free(tmp_address); + + return success; +} + +static const char *_unixsock_console_rasd_to_vdev(CMPIInstance *inst, + struct console_device *cdev) +{ + const char *val = NULL; + const char *val2 = NULL; + char* protocol = NULL; + + cdev->source_dev.unixsock.mode = NULL; + if (cu_get_str_prop(inst,"ConnectURL", &val) == CMPI_RC_OK) { + CU_DEBUG("ConnectURL = '%s'", val); + cdev->source_dev.unixsock.mode = strdup("connect"); + } + + if (cu_get_str_prop(inst, "BindURL", &val2) == CMPI_RC_OK) { + if (cdev->source_dev.unixsock.mode != NULL) + return "ConsoleRASD: Only ConnectURL or BindURL are allowed for " + "UNIX domain socket client/server.";
Not quite sure I understand the above check - are you checking that both Connect and Bind aren't being used? Then perhaps the message should state - cannot supply both ConnectURL and BindURL. Of course the above wording needs improvement ... agreed strdup() could fail, but that's a different issue...
+ CU_DEBUG("BindURL = '%s'", val2); + cdev->source_dev.unixsock.mode = strdup("bind"); + val = val2; + } + + if (val) { + if (!parse_console_url(val, &protocol, &cdev->source_dev.unixsock.path, NULL)) + return "ConsoleRASD: Invalid ConnectURL or BindURL for " + "UNIX domain socket client/server."; + + if (!STREQC("file", protocol)) { + CU_DEBUG("Wrong ConsoleRASD protocol specified: '%s'",protocol); + free(protocol); + return "ConsoleRASD: Protocol 'file' was not specified for " + "ConnectURL or BindURL for UNIX domain socket client/server."; + } + free(protocol); + } else
Prefer to see "} else {" as it's cleaner and no one mistakenly adds a line eventually. BTW: We could get here if strdup() fails...
agree [...]
+ + if (cu_get_str_prop(inst, "BindURL", &val2) == CMPI_RC_OK) { + if (cdev->source_dev.tcp.mode != NULL) + return "ConsoleRASD: Only ConnectURL or BindURL are allowed for " + "TCP client/server console.";
Similar comment from above - cannot supply both.
will do
+ CU_DEBUG("BindURL = '%s'",val2); + cdev->source_dev.tcp.mode = strdup("bind"); + val = val2; + } + + if (val) { + if (!parse_console_url(val, + &cdev->source_dev.tcp.protocol, + &cdev->source_dev.tcp.host, + &cdev->source_dev.tcp.service)) + return "ConsoleRASD: Invalid ConnectURL or BindURL for " + "TCP client/server console."; + if (cdev->source_dev.tcp.service == NULL) + return "ConsoleRASD: Missing TCP port for TCP client/server console."; + } else
Again the "} else {"
agree
+ return "ConsoleRASD: ConnectURL or BindURL not specified for " + "TCP client/server console."; + + if (STREQC("udp",cdev->source_dev.tcp.protocol)) { + CU_DEBUG("Wrong ConsoleRASD protocol specified: '%s'", cdev->source_dev.tcp.protocol); + return "ConsoleRASD: Invalid protocol 'udp' was specified at " + "TCP client/server console."; + } + + if (STREQC("file", cdev->source_dev.tcp.protocol)) { + CU_DEBUG("Wrong ConsoleRASD protocol specified: '%s'",cdev->source_dev.tcp.protocol); + return "ConsoleRASD: Invalid protocol 'file' was specified at " + "TCP client/server console."; + } + + return NULL; +} + +static const char *console_rasd_to_vdev(CMPIInstance *inst, + struct virt_device *dev) +{ + int rc = 0; + const char *msg = NULL; + const char *val = NULL; + struct console_device *cdev = &dev->dev.console; + uint16_t tmp; + + rc = cu_get_u16_prop(inst, "SourceType", &tmp); + if (rc != CMPI_RC_OK) + return "ConsoleRASD: SourceType field not specified."; + + if (tmp < 0 || tmp >= CIM_CHARDEV_SOURCE_TYPE_INVALIDTYPE)
tmp is a uint16_t so a < 0 comparison is not possible.
yep
+ return "ConsoleRASD: Invalid SourceType value"; + + cdev->source_type = tmp; + CU_DEBUG("Processeing SourceType: %d", cdev->source_type); + + /* property not required */ + if (cu_get_str_prop(inst, "TargetType", &val) == CMPI_RC_OK) + cdev->target_type = strdup(val); + CU_DEBUG("TargetType is '%s'", cdev->target_type);
More strdup/debug
Nothing overly serious - let me know how you want to proceed especially with respect to realloc() failure and unsigned compare less than zero
-> V2
-- Mit freundlichen Grüßen/Kind Regards Viktor Mihajlovski IBM Deutschland Research & Development GmbH Vorsitzender des Aufsichtsrats: Martina Köderitz Geschäftsführung: Dirk Wittkopp Sitz der Gesellschaft: Böblingen Registergericht: Amtsgericht Stuttgart, HRB 243294

From: Thilo Boehm <tboehm@linux.vnet.ibm.com> A new function to add a default console has been added. As with the default graphics and default input device, the default device generation is optional and depends on the domain type and architecture. Initially, we only create an s390 console, which is necessary to define a runnable guest. Signed-off-by: Thilo Boehm <tboehm@linux.vnet.ibm.com> Signed-off-by: Viktor Mihajlovski <mihajlov@linux.vnet.ibm.com> Reviewed-by: Boris Fiuczynski <fiuczy@linux.vnet.ibm.com> --- src/Virt_VirtualSystemManagementService.c | 34 +++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/Virt_VirtualSystemManagementService.c b/src/Virt_VirtualSystemManagementService.c index cd6ca9d..f835b47 100644 --- a/src/Virt_VirtualSystemManagementService.c +++ b/src/Virt_VirtualSystemManagementService.c @@ -592,6 +592,38 @@ static bool default_graphics_device(struct domain *domain) return true; } +static bool default_console_device(struct domain *domain) +{ + /* currently only taking care for s390 guests */ + if ((domain->type == DOMAIN_KVM || domain->type == DOMAIN_QEMU) && + domain->os_info.fv.arch != NULL && + (XSTREQ(domain->os_info.fv.arch, "s390") || + XSTREQ(domain->os_info.fv.arch, "s390x" ))) { + char * consoletype = NULL; + if (domain->os_info.fv.machine != NULL && + XSTREQ(domain->os_info.fv.machine, "s390-ccw-virtio")) { + consoletype = "sclp"; + } else { + consoletype = "virtio"; + } + free(domain->dev_console); + domain->dev_console = calloc(1, sizeof(*domain->dev_console)); + if (domain->dev_console == NULL) { + CU_DEBUG("Failed to allocate default console device."); + return false; + } + CU_DEBUG("Defining default console device for s390."); + domain->dev_console->type = CIM_RES_TYPE_CONSOLE; + domain->dev_console->dev.console.source_type = + CIM_CHARDEV_SOURCE_TYPE_PTY; + domain->dev_console->dev.console.target_type = + strdup(consoletype); + domain->dev_console_ct = 1; + } + + return true; +} + static bool default_input_device(struct domain *domain) { if (domain->type == DOMAIN_LXC) @@ -628,6 +660,8 @@ static bool add_default_devs(struct domain *domain) { if (domain->dev_graphics_ct < 1 && domain->dev_console_ct < 1) { + if (!default_console_device(domain)) + return false; if (!default_graphics_device(domain)) return false; } -- 1.7.9.5

On 09/05/2013 11:36 AM, Viktor Mihajlovski wrote:
From: Thilo Boehm <tboehm@linux.vnet.ibm.com>
A new function to add a default console has been added. As with the default graphics and default input device, the default device generation is optional and depends on the domain type and architecture. Initially, we only create an s390 console, which is necessary to define a runnable guest.
Signed-off-by: Thilo Boehm <tboehm@linux.vnet.ibm.com> Signed-off-by: Viktor Mihajlovski <mihajlov@linux.vnet.ibm.com> Reviewed-by: Boris Fiuczynski <fiuczy@linux.vnet.ibm.com> --- src/Virt_VirtualSystemManagementService.c | 34 +++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+)
ACK John FYI: The not checking for memory allocation is endemic throughout libvirt-cim. I suppose "some day" it would be good to do something about it, but there's so many assumptions now it'd probably take the libvirt VIR_ALLOC, VIR_STRDUP, etc macros to fix all the instances.

On 09/05/2013 11:36 AM, Viktor Mihajlovski wrote:
Motivation: the current libvirt-cim support for consoles is very limited in that it doesn't allow to specify the target and source types supported by libvirt. Having full support of the libvirt console feature is however mandatory for architectures like s390.
The current implementation using a Graphics_RASD to represent consoles cannot easily be extended without breaking the existing implementation (or without being entirely unusable).
Therefore a new RASD class is added to represent consoles in the model. Since there's no SVPC resource type for a console we use the combination of ResourceType = 1 (Other) and OtherResourceType = "console" for the new RASD instances.
In order to be backward compatible, the only console type supported by older libvirt-cim versions (target type 'pty') will still be returned as Graphics_RASD. In the long run, this should be deprecated.
Thilo Boehm (6): schema: Add CIM_ResourceAllocationSettingData for console resources schema: New SVPC types for chardev/consoles libxkutil: Console Support RASD: Provider Support for Console RASDs VSMS: Support for domains with console devices VSMS: add default console
Viktor Mihajlovski (2): VSMS: Set resource types for default devices Device: CIM_LogicalDevice for consoles
libxkutil/device_parsing.c | 316 ++++++++++++++++++- libxkutil/device_parsing.h | 43 ++- libxkutil/xmlgen.c | 191 +++++++++++- schema/ResourceAllocationSettingData.mof | 247 ++++++++++++++- schema/ResourceAllocationSettingData.registration | 5 +- src/Virt_Device.c | 33 ++ src/Virt_RASD.c | 148 ++++++++- src/Virt_VirtualSystemManagementService.c | 336 +++++++++++++++++++-- src/svpc_types.h | 102 ++++++- 9 files changed, 1384 insertions(+), 37 deletions(-)
Not quite sure where it is, but there is a bug somewhere in patches 2->5 as the cimtest 'RASD' for '03_rasd_errs.py' fails to find/add the console device. The error message is "Expected 7 RASDs, got 6". I also think there's an ordering problem. If I add the patches 1 at a time, patch #2 will cause the same cimtest to return 0 (zero) RASD's (as found through debugging the cimtest test) if patches 3 and 4 are applied. I decided to try an experiment to see if I could narrow things down. The experiment was add each patch 1 at a time, then add patch 2 to the set. 1,3 -> Returns found 6, then add patch 2 and returns found 0 RASD's 1,3,4 -> Returns found 6, then add patch 2 and returns found 0 RASD's 1,3,4,5 -> Returns found 6, then add patch 2 and returns expected 7 found 6 At the very least patch 2 needs to go after patch 5 or be merged with patch 5 since it seems that's where the connection/implementation occurs. I didn't dig deep into that test to try and figure out why the console device was "missing". John

On 09/09/2013 04:02 PM, John Ferlan wrote:
Not quite sure where it is, but there is a bug somewhere in patches 2->5 as the cimtest 'RASD' for '03_rasd_errs.py' fails to find/add the console device. The error message is "Expected 7 RASDs, got 6".
I also think there's an ordering problem. If I add the patches 1 at a time, patch #2 will cause the same cimtest to return 0 (zero) RASD's (as found through debugging the cimtest test) if patches 3 and 4 are applied.
I decided to try an experiment to see if I could narrow things down. The experiment was add each patch 1 at a time, then add patch 2 to the set.
1,3 -> Returns found 6, then add patch 2 and returns found 0 RASD's 1,3,4 -> Returns found 6, then add patch 2 and returns found 0 RASD's 1,3,4,5 -> Returns found 6, then add patch 2 and returns expected 7 found 6
At the very least patch 2 needs to go after patch 5 or be merged with patch 5 since it seems that's where the connection/implementation occurs.
I didn't dig deep into that test to try and figure out why the console device was "missing".
Strange, I have not seen this 6/7 message. This means that the test domain has less RASD types than RASD types found on the system. Can it be that you have some domain already defined before you run cimtest? This might explain the behavior (but would be a bug in cimtest). As for the patch grouping, it was meant to make the patches more readable rather than to be technically necessary. In fact, the provider patches (5,6,7) and the MOF/schemal patch (2) must go together. I can squash them in a V2, but this could in my opinion wait until I get more feedback. Could you do me a favor and apply this here, rerun the RASD test group and paste the resulting cimtest.log from the RASD directory? Thanks! -- diff --git a/suites/libvirt-cim/cimtest/RASD/03_rasd_errs.py b/suites/libvirt-cim/cimtest/RASD/03_rasd_errs.py index d582ffb..024b0ae 100644 --- a/suites/libvirt-cim/cimtest/RASD/03_rasd_errs.py +++ b/suites/libvirt-cim/cimtest/RASD/03_rasd_errs.py @@ -68,9 +68,11 @@ def init_rasd_list(virt, ip, guest_name): logger.error("Unable to parse InstanceID: %s" % rasd.InstanceID) return rasd_insts, FAIL + logger.info("RASD found %s for %s", rasd.Classname, guest) if guest == guest_name: rasd_insts[rasd.Classname] = rasd - + + logger.info("Expected %d RASDs, got %d", len(rasds), len(rasd_insts)) if len(rasds) != len(rasd_insts): logger.error("Expected %d RASDs, got %d", len(rasds), len(rasd_insts)) return rasd_insts, FAIL Mit freundlichen Grüßen/Kind Regards Viktor Mihajlovski IBM Deutschland Research & Development GmbH Vorsitzender des Aufsichtsrats: Martina Köderitz Geschäftsführung: Dirk Wittkopp Sitz der Gesellschaft: Böblingen Registergericht: Amtsgericht Stuttgart, HRB 243294

On 09/10/2013 05:35 AM, Viktor Mihajlovski wrote:
On 09/09/2013 04:02 PM, John Ferlan wrote:
<... snip ...>
Strange, I have not seen this 6/7 message. This means that the test domain has less RASD types than RASD types found on the system. Can it be that you have some domain already defined before you run cimtest? This might explain the behavior (but would be a bug in cimtest).
Sure I have other domains defined already on the test system, one of them is running. It's strange that the only domain to not get a console rasd is the test domain. I did find a bug in the 03*.py code - if there's an error from init_rasd_list, the code returns without undefining the domain. The fix would be: rasds, status = init_rasd_list(virt, options.ip, test_dom) if status != PASS: logger.error("Unable to build rasd instance list") + vsxml.undefine(server) return status But doing that still does not resolve the problem.
As for the patch grouping, it was meant to make the patches more readable rather than to be technically necessary. In fact, the provider patches (5,6,7) and the MOF/schemal patch (2) must go together. I can squash them in a V2, but this could in my opinion wait until I get more feedback.
That's fine - just want to make sure that at each stage of patch application that we have functioning code. Makes the git bisect much easier when/if there are problems...
Could you do me a favor and apply this here, rerun the RASD test group and paste the resulting cimtest.log from the RASD directory? Thanks!
For whatever reason logger.info didn't spit out the messages, so I changed using to logger.error... I also added a printing of rasds and rasds_inst -------------------------------------------------------------------- RASD - 03_rasd_errs.py: FAIL ERROR - RASD found KVM_InputResourceAllocationSettingData for if18lcl ERROR - RASD found KVM_InputResourceAllocationSettingData for if18lcl ERROR - RASD found KVM_InputResourceAllocationSettingData for VSSDC_dom ERROR - RASD found KVM_InputResourceAllocationSettingData for rh70-alpha3 ERROR - RASD found KVM_InputResourceAllocationSettingData for rh70-alpha3 ERROR - RASD found KVM_InputResourceAllocationSettingData for if18net ERROR - RASD found KVM_InputResourceAllocationSettingData for rh64 ERROR - RASD found KVM_InputResourceAllocationSettingData for rh64 ERROR - RASD found KVM_InputResourceAllocationSettingData for if18nopool ERROR - RASD found KVM_InputResourceAllocationSettingData for if18nopool ERROR - RASD found KVM_InputResourceAllocationSettingData for f18 ERROR - RASD found KVM_InputResourceAllocationSettingData for f18 ERROR - RASD found KVM_ProcResourceAllocationSettingData for if18lcl ERROR - RASD found KVM_ProcResourceAllocationSettingData for VSSDC_dom ERROR - RASD found KVM_ProcResourceAllocationSettingData for rhel65-f18 ERROR - RASD found KVM_ProcResourceAllocationSettingData for rh70-alpha3 ERROR - RASD found KVM_ProcResourceAllocationSettingData for if18net ERROR - RASD found KVM_ProcResourceAllocationSettingData for rh64 ERROR - RASD found KVM_ProcResourceAllocationSettingData for if18nopool ERROR - RASD found KVM_ProcResourceAllocationSettingData for f18 ERROR - RASD found KVM_ConsoleResourceAllocationSettingData for if18lcl ERROR - RASD found KVM_ConsoleResourceAllocationSettingData for rhel65-f18 ERROR - RASD found KVM_ConsoleResourceAllocationSettingData for rh70-alpha3 ERROR - RASD found KVM_ConsoleResourceAllocationSettingData for if18net ERROR - RASD found KVM_ConsoleResourceAllocationSettingData for rh64 ERROR - RASD found KVM_ConsoleResourceAllocationSettingData for if18nopool ERROR - RASD found KVM_ConsoleResourceAllocationSettingData for f18 ERROR - RASD found KVM_DiskResourceAllocationSettingData for if18lcl ERROR - RASD found KVM_DiskResourceAllocationSettingData for VSSDC_dom ERROR - RASD found KVM_DiskResourceAllocationSettingData for rhel65-f18 ERROR - RASD found KVM_DiskResourceAllocationSettingData for rhel65-f18 ERROR - RASD found KVM_DiskResourceAllocationSettingData for rh70-alpha3 ERROR - RASD found KVM_DiskResourceAllocationSettingData for if18net ERROR - RASD found KVM_DiskResourceAllocationSettingData for rh64 ERROR - RASD found KVM_DiskResourceAllocationSettingData for f18 ERROR - RASD found KVM_DiskResourceAllocationSettingData for f18 ERROR - RASD found KVM_MemResourceAllocationSettingData for if18lcl ERROR - RASD found KVM_MemResourceAllocationSettingData for VSSDC_dom ERROR - RASD found KVM_MemResourceAllocationSettingData for rhel65-f18 ERROR - RASD found KVM_MemResourceAllocationSettingData for rh70-alpha3 ERROR - RASD found KVM_MemResourceAllocationSettingData for if18net ERROR - RASD found KVM_MemResourceAllocationSettingData for rh64 ERROR - RASD found KVM_MemResourceAllocationSettingData for if18nopool ERROR - RASD found KVM_MemResourceAllocationSettingData for f18 ERROR - RASD found KVM_NetResourceAllocationSettingData for if18lcl ERROR - RASD found KVM_NetResourceAllocationSettingData for VSSDC_dom ERROR - RASD found KVM_NetResourceAllocationSettingData for rhel65-f18 ERROR - RASD found KVM_NetResourceAllocationSettingData for rh70-alpha3 ERROR - RASD found KVM_NetResourceAllocationSettingData for if18net ERROR - RASD found KVM_NetResourceAllocationSettingData for rh64 ERROR - RASD found KVM_NetResourceAllocationSettingData for if18nopool ERROR - RASD found KVM_NetResourceAllocationSettingData for f18 ERROR - RASD found KVM_GraphicsResourceAllocationSettingData for if18lcl ERROR - RASD found KVM_GraphicsResourceAllocationSettingData for if18lcl ERROR - RASD found KVM_GraphicsResourceAllocationSettingData for VSSDC_dom ERROR - RASD found KVM_GraphicsResourceAllocationSettingData for rhel65-f18 ERROR - RASD found KVM_GraphicsResourceAllocationSettingData for rh70-alpha3 ERROR - RASD found KVM_GraphicsResourceAllocationSettingData for rh70-alpha3 ERROR - RASD found KVM_GraphicsResourceAllocationSettingData for if18net ERROR - RASD found KVM_GraphicsResourceAllocationSettingData for if18net ERROR - RASD found KVM_GraphicsResourceAllocationSettingData for rh64 ERROR - RASD found KVM_GraphicsResourceAllocationSettingData for rh64 ERROR - RASD found KVM_GraphicsResourceAllocationSettingData for if18nopool ERROR - RASD found KVM_GraphicsResourceAllocationSettingData for if18nopool ERROR - RASD found KVM_GraphicsResourceAllocationSettingData for f18 ERROR - expected 7 RASDs, got 6 ERROR - Expected 7 RASDs, got 6 ERROR - Unable to build rasd instance list rasds has: KVM_InputResourceAllocationSettingData KVM_ProcResourceAllocationSettingData KVM_ConsoleResourceAllocationSettingData KVM_DiskResourceAllocationSettingData KVM_MemResourceAllocationSettingData KVM_NetResourceAllocationSettingData KVM_GraphicsResourceAllocationSettingData rasd_insts has: KVM_DiskResourceAllocationSettingData KVM_ProcResourceAllocationSettingData KVM_MemResourceAllocationSettingData KVM_NetResourceAllocationSettingData KVM_InputResourceAllocationSettingData KVM_GraphicsResourceAllocationSettingData --------------------------------------------------------------------

cimtest).
Sure I have other domains defined already on the test system, one of them is running. It's strange that the only domain to not get a console rasd is the test domain.
On 09/10/2013 06:02 PM, John Ferlan wrote: that's actually to be expected, since the testsuite doesn't yet contain support for test domains with a console, I am currently testing a patch that will change this
I did find a bug in the 03*.py code - if there's an error from init_rasd_list, the code returns without undefining the domain. The fix would be:
rasds, status = init_rasd_list(virt, options.ip, test_dom) if status != PASS: logger.error("Unable to build rasd instance list") + vsxml.undefine(server) return status
But doing that still does not resolve the problem.
For whatever reason logger.info didn't spit out the messages, so I changed using to logger.error... I also added a printing of rasds and rasds_inst logger.info doesn't write to the console, only into suites/libvirt-cim/cimtest/$TESTGROUP/cimtest.log
-------------------------------------------------------------------- RASD - 03_rasd_errs.py: FAIL ERROR - RASD found KVM_InputResourceAllocationSettingData for if18lcl ERROR - RASD found KVM_InputResourceAllocationSettingData for if18lcl ERROR - RASD found KVM_InputResourceAllocationSettingData for VSSDC_dom ERROR - RASD found KVM_InputResourceAllocationSettingData for rh70-alpha3 ERROR - RASD found KVM_InputResourceAllocationSettingData for rh70-alpha3 ERROR - RASD found KVM_InputResourceAllocationSettingData for if18net ERROR - RASD found KVM_InputResourceAllocationSettingData for rh64 ERROR - RASD found KVM_InputResourceAllocationSettingData for rh64 ERROR - RASD found KVM_InputResourceAllocationSettingData for if18nopool ERROR - RASD found KVM_InputResourceAllocationSettingData for if18nopool ERROR - RASD found KVM_InputResourceAllocationSettingData for f18 ERROR - RASD found KVM_InputResourceAllocationSettingData for f18 ERROR - RASD found KVM_ProcResourceAllocationSettingData for if18lcl ERROR - RASD found KVM_ProcResourceAllocationSettingData for VSSDC_dom ERROR - RASD found KVM_ProcResourceAllocationSettingData for rhel65-f18 ERROR - RASD found KVM_ProcResourceAllocationSettingData for rh70-alpha3 ERROR - RASD found KVM_ProcResourceAllocationSettingData for if18net ERROR - RASD found KVM_ProcResourceAllocationSettingData for rh64 ERROR - RASD found KVM_ProcResourceAllocationSettingData for if18nopool ERROR - RASD found KVM_ProcResourceAllocationSettingData for f18 ERROR - RASD found KVM_ConsoleResourceAllocationSettingData for if18lcl ERROR - RASD found KVM_ConsoleResourceAllocationSettingData for rhel65-f18 ERROR - RASD found KVM_ConsoleResourceAllocationSettingData for rh70-alpha3 ERROR - RASD found KVM_ConsoleResourceAllocationSettingData for if18net ERROR - RASD found KVM_ConsoleResourceAllocationSettingData for rh64 ERROR - RASD found KVM_ConsoleResourceAllocationSettingData for if18nopool ERROR - RASD found KVM_ConsoleResourceAllocationSettingData for f18
nice finding, for the rest see below the domains above do have a serial or console definition and therefore show up in the first RASD enumeration ... as I have pointed out before, the VSSC_dom is plainly defined without a console by the testsuite, so it is perfectly correct for it not to show up above. Which means that the 03_xxx testcase is broken, as it should check whether the domain has the RASDs that are to be expected instead of a RASD of each type discovered on the system. Will try to fix this as well in the cimtest patch I'm working on -- Mit freundlichen Grüßen/Kind Regards Viktor Mihajlovski IBM Deutschland Research & Development GmbH Vorsitzender des Aufsichtsrats: Martina Köderitz Geschäftsführung: Dirk Wittkopp Sitz der Gesellschaft: Böblingen Registergericht: Amtsgericht Stuttgart, HRB 243294

On 09/10/2013 12:21 PM, Viktor Mihajlovski wrote:
as I have pointed out before, the VSSC_dom is plainly defined without a console by the testsuite, so it is perfectly correct for it not to show up above. Which means that the 03_xxx testcase is broken, as it should check whether the domain has the RASDs that are to be expected instead of a RASD of each type discovered on the system. Will try to fix this as well in the cimtest patch I'm working on
So essentially the following test is completely bogus as it's not testing anything other than a domain having all types of available RASDs in the environment: if len(rasds) != len(rasd_insts): logger.error("Expected %d RASDs, got %d", len(rasds), len(rasd_insts)) return rasd_insts, FAIL If anything what it should be doing is if (len(rasds_insts == 0): logger.error("Found 0 RASDs for %s", guest_name) return rasd_insts, FAIL Not quite sure how one would determine how many are expected though without knowing a bit more about the definition of the guest. John

The number of expected RASDs for the test domain was incorrectly computed by enumerating all RASDs on the hypervisor which will always fail if the test domain doesn't have every possible RASD associated. Fixed by counting the resource settings in the virtual server instance and comparing that against the RASDs actually found. Signed-off-by: Viktor Mihajlovski <mihajlov@linux.vnet.ibm.com> --- suites/libvirt-cim/cimtest/RASD/03_rasd_errs.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/suites/libvirt-cim/cimtest/RASD/03_rasd_errs.py b/suites/libvirt-cim/cimtest/RASD/03_rasd_errs.py index d582ffb..5517a72 100644 --- a/suites/libvirt-cim/cimtest/RASD/03_rasd_errs.py +++ b/suites/libvirt-cim/cimtest/RASD/03_rasd_errs.py @@ -71,10 +71,6 @@ def init_rasd_list(virt, ip, guest_name): if guest == guest_name: rasd_insts[rasd.Classname] = rasd - if len(rasds) != len(rasd_insts): - logger.error("Expected %d RASDs, got %d", len(rasds), len(rasd_insts)) - return rasd_insts, FAIL - return rasd_insts, PASS @do_main(sup_types) @@ -106,6 +102,11 @@ def main(): logger.error("Unable to build rasd instance list") return status + if len(vsxml.res_settings) != len(rasds): + logger.error("Expected %d RASDs, got %d", len(vsxml.res_settings), + len(rasds)) + return FAIL + expr_values = { 'rc' : CIM_ERR_NOT_FOUND, 'desc' : 'No such instance' -- 1.7.9.5

On 09/11/2013 05:43 AM, Viktor Mihajlovski wrote:
The number of expected RASDs for the test domain was incorrectly computed by enumerating all RASDs on the hypervisor which will always fail if the test domain doesn't have every possible RASD associated. Fixed by counting the resource settings in the virtual server instance and comparing that against the RASDs actually found.
Signed-off-by: Viktor Mihajlovski <mihajlov@linux.vnet.ibm.com> --- suites/libvirt-cim/cimtest/RASD/03_rasd_errs.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/suites/libvirt-cim/cimtest/RASD/03_rasd_errs.py b/suites/libvirt-cim/cimtest/RASD/03_rasd_errs.py index d582ffb..5517a72 100644 --- a/suites/libvirt-cim/cimtest/RASD/03_rasd_errs.py +++ b/suites/libvirt-cim/cimtest/RASD/03_rasd_errs.py @@ -71,10 +71,6 @@ def init_rasd_list(virt, ip, guest_name): if guest == guest_name: rasd_insts[rasd.Classname] = rasd
- if len(rasds) != len(rasd_insts): - logger.error("Expected %d RASDs, got %d", len(rasds), len(rasd_insts)) - return rasd_insts, FAIL - return rasd_insts, PASS
@do_main(sup_types) @@ -106,6 +102,11 @@ def main(): logger.error("Unable to build rasd instance list") return status
+ if len(vsxml.res_settings) != len(rasds): + logger.error("Expected %d RASDs, got %d", len(vsxml.res_settings), + len(rasds)) + return FAIL + expr_values = { 'rc' : CIM_ERR_NOT_FOUND, 'desc' : 'No such instance'
ACK and pushed with the following change to account for the error paths not undefining the guest: diff --git a/suites/libvirt-cim/cimtest/RASD/03_rasd_errs.py b/suites/libvirt-ci index 5517a72..feec39b 100644 --- a/suites/libvirt-cim/cimtest/RASD/03_rasd_errs.py +++ b/suites/libvirt-cim/cimtest/RASD/03_rasd_errs.py @@ -100,11 +100,13 @@ def main(): rasds, status = init_rasd_list(virt, options.ip, test_dom) if status != PASS: logger.error("Unable to build rasd instance list") + vsxml.undefine(server) return status if len(vsxml.res_settings) != len(rasds): logger.error("Expected %d RASDs, got %d", len(vsxml.res_settings), len(rasds)) + vsxml.undefine(server) return FAIL expr_values = { John
participants (2)
-
John Ferlan
-
Viktor Mihajlovski