diff mbox series

[RFC,5/5] CXL FM: [fm_cli] introduce CXL FM CLI tool

Message ID 20230602213737.494750-6-slava@dubeyko.com
State New, archived
Headers show
Series CXL FM initial infrastructure | expand

Commit Message

Viacheslav Dubeyko June 2, 2023, 9:37 p.m. UTC
This patch creates the initial state of CXL FM CLI tool.

Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>
CC: Adam Manzanares <a.manzanares@samsung.com>
---
 Cargo.toml                            |   4 +
 ChangeLog                             |   6 +
 README                                | 226 ++++++++
 fm_cli/Cargo.toml                     |  10 +
 fm_cli/src/discover.rs                | 159 ++++++
 fm_cli/src/dynamic_capacity_device.rs | 225 ++++++++
 fm_cli/src/fm.rs                      | 258 +++++++++
 fm_cli/src/logical_device.rs          | 489 +++++++++++++++++
 fm_cli/src/main.rs                    | 721 ++++++++++++++++++++++++++
 fm_cli/src/mld_port.rs                | 126 +++++
 fm_cli/src/multi_headed_device.rs     |  60 +++
 fm_cli/src/pci2pci_bridge.rs          | 126 +++++
 fm_cli/src/physical_port.rs           | 159 ++++++
 fm_cli/src/switch.rs                  | 126 +++++
 14 files changed, 2695 insertions(+)
 create mode 100644 ChangeLog
 create mode 100644 README
 create mode 100644 fm_cli/Cargo.toml
 create mode 100644 fm_cli/src/discover.rs
 create mode 100644 fm_cli/src/dynamic_capacity_device.rs
 create mode 100644 fm_cli/src/fm.rs
 create mode 100644 fm_cli/src/logical_device.rs
 create mode 100644 fm_cli/src/main.rs
 create mode 100644 fm_cli/src/mld_port.rs
 create mode 100644 fm_cli/src/multi_headed_device.rs
 create mode 100644 fm_cli/src/pci2pci_bridge.rs
 create mode 100644 fm_cli/src/physical_port.rs
 create mode 100644 fm_cli/src/switch.rs
diff mbox series

Patch

diff --git a/Cargo.toml b/Cargo.toml
index ed50825..6eac9cd 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -9,6 +9,10 @@  edition = "2021"
 name = "fm_library"
 path = "fm_library/src/lib.rs"
 
+[[bin]]
+name = "fm_cli"
+path = "fm_cli/src/main.rs"
+
 [[bin]]
 name = "fm_daemon"
 path = "fm_daemon/src/main.rs"
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..590513a
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,6 @@ 
+********************************************************************************
+*                            CHANGELOG SECTION                                 *
+********************************************************************************
+
+v.0.01 [June 02, 2023]
+    (*) Create initial state [Viacheslav Dubeyko].
diff --git a/README b/README
new file mode 100644
index 0000000..b93d2af
--- /dev/null
+++ b/README
@@ -0,0 +1,226 @@ 
+CXL Fabric Manager (FM) infrastructure
+
+CXL Fabric Manager (FM) is the application logic responsible for
+system composition and allocation of resources. The FM can be embedded
+in the firmware of a device such as a CXL switch, reside on a host,
+or could be run on a Baseboard Management Controller (BMC).
+CXL Specification 3.0 defines Fabric Management as: "CXL devices can be
+configured statically or dynamically via a Fabric Manager (FM),
+an external logical process that queries and configures the system’s
+operational state using the FM commands defined in this specification.
+The FM is defined as the logical process that decides when
+reconfiguration is necessary and initiates the commands to perform
+configurations. It can take any form, including, but not limited to,
+software running on a host machine, embedded software running on a BMC,
+embedded firmware running on another CXL device or CXL switch,
+or a state machine running within the CXL device itself.".
+
+CXL devices are configured by FM through the Fabric Manager Application
+Programming Interface (FM API) command sets through a CCI (Component
+Command Interface). A CCI is exposed through a device’s Mailbox registers
+or through an MCTP-capable (Management Component Transport Protocol)
+interface.
+
+FM API Commands (defined by CXL Specification 3.0):
+(1) Physical switch
+    - Identify Switch Device,
+    - Get Physical Port State,
+    - Physical Port Control,
+    - Send PPB (PCI-to-PCI Bridge) CXL.io Configuration Request.
+(2) Virtual Switch
+    - Get Virtual CXL Switch Info,
+    - Bind vPPB (Virtual PCI-to-PCI Bridge),
+    - Unbind vPPB,
+    - Generate AER (Advanced Error Reporting Event).
+(3) MLD Port
+    - Tunnel Management Command,
+    - Send LD (Logical Device) or FMLD (Fabric Manager-owned Logical Device)
+      CXL.io Configuration Request,
+    - Send LD CXL.io Memory Request.
+(4) MLD Components
+    - Get LD (Logical Device) Info,
+    - Get LD Allocations,
+    - Set LD Allocations,
+    - Get QoS Control,
+    - Set QoS Control,
+    - Get QoS Status,
+    - Get QoS Allocated Bandwidth,
+    - Set QoS Allocated Bandwidth,
+    - Get QoS Bandwidth Limit,
+    - Set QoS Bandwidth Limit.
+(5) Multi- Headed Devices (Get Multi-Headed Info).
+(6) DCD (Dynamic Capacity Device) Management
+    - Get DCD Info,
+    - Get Host Dynamic Capacity Region Configuration,
+    - Set Dynamic Capacity Region Configuration,
+    - Get DCD Extent Lists,
+    - Initiate Dynamic Capacity Add,
+    - Initiate Dynamic Capacity Release.
+
+After the initial configuration is complete and a CCI on the switch is
+operational, an FM can send Management Commands to the switch.
+
+An FM may perform the following dynamic management actions on a CXL switch:
+(1) Query switch information and configuration details,
+(2) Bind or Unbind ports,
+(3) Register to receive and handle event notifications from the switch
+    (e.g., hot plug, surprise removal, and failures).
+
+A switch with MLD (Multi-Logical Device) requires an FM to perform
+the following management activities:
+(1) MLD discovery,
+(2) LD (Logical Device) binding/unbinding,
+(3) Management Command Tunneling.
+
+The FM can connect to an MLD (Multi-Logical Device) over a direct connection or
+by tunneling its management commands through the CCI of the CXL switch
+to which the device is connected. The FM can perform the following
+operations:
+(1) Memory allocation and QoS Telemetry management,
+(2) Security (e.g., LD erasure after unbinding),
+(3) Error handling.
+
+fm_cli - FM configuration tool
+Commands:
+
+Discover - discover available agents
+Subcommands:
+    - fm_cli discover fm
+         (discover FM instances)
+    - fm_cli discover cxl_devices
+         (discover CXL devices)
+    - fm_cli discover cxl_switches
+         (discover CXL switches)
+    - fm_cli discover logical_devices
+         (discover logical devices)
+
+FM - manage Fabric Manager
+Subcommands:
+    - fm_cli fm get_info
+         (get FM status/info)
+    - fm_cli fm start
+         (start FM instance)
+    - fm_cli fm restart
+         (restart FM instance)
+    - fm_cli fm stop
+         (stop FM instance)
+    - fm_cli fm get_config
+         (get FM configuration)
+    - fm_cli fm set_config
+         (set FM configuration)
+    - fm_cli fm get_events
+         (get event records)
+
+Switch - manage CXL switch
+Subcommands:
+    - fm_cli switch get_info
+         (get CXL switch info/status)
+    - fm_cli switch get_config
+         (get switch configuraiton)
+    - fm_cli switch set_config
+         (set switch configuration)
+
+Logical Device - manage logical devices
+Subcommands:
+    - fm_cli multi_headed_device info
+         (retrieves the number of heads, number of supported LDs,
+          and Head-to-LD mapping of a Multi-Headed device)
+    - fm_cli logical_device bind
+         (bind logical device)
+    - fm_cli logical_device unbind
+         (unbind logical device)
+    - fm_cli logical_device connect
+         (connect Multi Logical Device to CXL switch)
+    - fm_cli logical_device disconnect
+         (disconnect Multi Logical Device from CXL switch)
+    - fm_cli logical_device get_allocation
+         (Get LD Allocations: retrieves the memory allocations of the MLD)
+    - fm_cli logical_device set_allocation
+         (Set LD Allocations: sets the memory allocation for each LD)
+    - fm_cli logical_device get_qos_control
+         (Get QoS Control: retrieves the MLD’s QoS control parameters)
+    - fm_cli logical_device set_qos_control
+         (Set QoS Control: sets the MLD’s QoS control parameters)
+    - fm_cli logical_device get_qos_status
+         (Get QoS Status: retrieves the MLD’s QoS Status)
+    - fm_cli logical_device get_qos_allocated_bandwidth
+         (Get QoS Allocated Bandwidth: retrieves the MLD’s QoS allocated
+          bandwidth on a per-LD basis)
+    - fm_cli logical_device set_qos_allocated_bandwidth
+         (Set QoS Allocated Bandwidth: sets the MLD’s QoS allocated bandwidth
+          on a per-LD basis)
+    - fm_cli logical_device get_qos_bandwidth_limit
+         (Get QoS Bandwidth Limit: retrieves the MLD’s QoS bandwidth limit
+          on a per-LD basis)
+    - fm_cli logical_device set_qos_bandwidth_limit
+         (Set QoS Bandwidth Limit: sets the MLD’s QoS bandwidth limit
+          on a per-LD basis)
+    - fm_cli logical_device erase
+         (secure erase after unbinding)
+
+PCI-to-PCI Bridge - manage PPB (PCI-to-PCI Bridge)
+Subcommands:
+    - fm_cli ppb config
+         (Send PPB (PCI-to-PCI Bridge) CXL.io Configuration Request)
+    - fm_cli ppb bind
+         (Bind vPPB: Virtual PCI-to-PCI Bridge inside a CXL switch
+          that is host-owned)
+    - fm_cli ppb unbind
+         (Unbind vPPB: unbinds the physical port or LD from the virtual
+          hierarchy PPB)
+
+Physical Port - manage physical ports
+Subcommands:
+    - fm_cli physical_port get_info
+         (get state of physical port)
+    - fm_cli physical_port control
+         (control unbound ports and MLD ports, including issuing
+          resets and controlling sidebands)
+    - fm_cli physical_port bind
+         (bind physical port to vPPB (Virtual PCI-to-PCI Bridge))
+    - fm_cli physical_port unbind
+         (unbind physical port from vPPB (Virtual PCI-to-PCI Bridge))
+
+MLD (Multi-Logical Device) Port - manage Multi-Logical Device ports
+Subcommands:
+    - fm_cli mld_port tunnel
+         (Tunnel Management Command: tunnels the provided command to
+          LD FFFFh of the MLD on the specified port)
+    - fm_cli mld_port send_config
+         (Send LD (Logical Device) or FMLD (Fabric Manager-owned
+          Logical Device) CXL.io Configuration Request)
+    - fm_cli mld_port send_memory_request
+         (Send LD CXL.io Memory Request)
+
+DCD (Dynamic Capacity Device) - manage Dynamic Capacity Device
+Subcommands:
+    - fm_cli dcd get_info
+         (Get DCD Info: retrieves the number of supported hosts,
+          total Dynamic Capacity of the device, and supported region
+          configurations)
+    - fm_cli dcd get_capacity_config
+         (Get Host Dynamic Capacity Region Configuration: retrieves
+          the Dynamic Capacity configuration for a specified host)
+    - fm_cli dcd set_capacity_config
+         (Set Dynamic Capacity Region Configuration: sets
+          the configuration of a DC Region)
+    - fm_cli dcd get_extent_list
+         (Get DCD Extent Lists: retrieves the Dynamic Capacity Extent
+          List for a specified host)
+    - fm_cli dcd add_capacity
+         (Initiate Dynamic Capacity Add: initiates the addition of
+          Dynamic Capacity to the specified region on a host)
+    - fm_cli dcd release_capacity
+         (Initiate Dynamic Capacity Release: initiates the release of
+          Dynamic Capacity from a host)
+
+FM daemon receives requests from configuration tool and executes
+commands by means of interaction with kernel-space subsystems.
+The responsibility of FM daemon:
+    - Execute configuration tool commands
+    - Manage hot-add and hot-removal of devices
+    - Manage surprise removal of devices
+    - Receive and handle even notifications from the CXL switch
+    - Logging events
+    - Memory allocation and QoS Telemetry management
+    - Error/Failure handling
diff --git a/fm_cli/Cargo.toml b/fm_cli/Cargo.toml
new file mode 100644
index 0000000..e619a63
--- /dev/null
+++ b/fm_cli/Cargo.toml
@@ -0,0 +1,10 @@ 
+[package]
+name = "fm_cli"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+clap = { version = "4.0.32", features = ["derive"] }
+fm_library = { path = "../fm_library/" }
\ No newline at end of file
diff --git a/fm_cli/src/discover.rs b/fm_cli/src/discover.rs
new file mode 100644
index 0000000..a06889f
--- /dev/null
+++ b/fm_cli/src/discover.rs
@@ -0,0 +1,159 @@ 
+/*
+ * CXL FM Infrastructure -- CXl Fabric Manager (FM) Infrastructure.
+ *
+ * CXL FM configuration tool implementation.
+ *
+ * Copyright (c) 2023 Viacheslav Dubeyko <slava@dubeyko.com>,
+ * All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+pub mod cxl_fm_discover_command {
+	use clap::{ArgMatches};
+	use std::net::{TcpStream};
+	use fm_library::cxl_fm_lib::CxlFmOptions;
+	use fm_library::cxl_fm_lib::send_command;
+	use fm_library::cxl_fm_lib::CXL_FM_DISCOVER_FM_COMMAND;
+	use fm_library::cxl_fm_lib::CXL_FM_DISCOVER_CXL_DEVICE_COMMAND;
+	use fm_library::cxl_fm_lib::CXL_FM_DISCOVER_CXL_SWITCH_COMMAND;
+	use fm_library::cxl_fm_lib::CXL_FM_DISCOVER_LD_COMMAND;
+
+	/*
+	 * Discover available FM instances
+	 */
+	pub fn discover_fms(options: &ArgMatches, env: &CxlFmOptions) {
+		if env.is_debug {
+			println!("{}", crate::CXL_FM_DISCOVER_FM_COMMAND_DESCRIPTOR);
+		}
+
+		if options.args_present() {
+			/*
+			 * Ignore currently.
+			 * Add code later.
+			 */
+		}
+
+		match TcpStream::connect(&env.ip_port) {
+			Ok(mut stream) => {
+				if env.is_debug {
+					println!("Successfully connected to server: {}",
+						 env.ip_port);
+				}
+
+				send_command(&mut stream,
+					     CXL_FM_DISCOVER_FM_COMMAND,
+					     &env);
+			},
+			Err(e) => {
+				println!("Failed to connect: {}", e);
+			}
+		}
+	}
+
+	/*
+	 * Discover available CXL devices
+	 */
+	pub fn discover_cxl_devices(options: &ArgMatches, env: &CxlFmOptions) {
+		if env.is_debug {
+			println!("{}", crate::CXL_FM_DISCOVER_DEVICES_COMMAND_DESCRIPTOR);
+		}
+
+		if options.args_present() {
+			/*
+			 * Ignore currently.
+			 * Add code later.
+			 */
+		}
+
+		match TcpStream::connect(&env.ip_port) {
+			Ok(mut stream) => {
+				if env.is_debug {
+					println!("Successfully connected to server: {}",
+						 env.ip_port);
+				}
+
+				send_command(&mut stream,
+					     CXL_FM_DISCOVER_CXL_DEVICE_COMMAND,
+					     &env);
+			},
+			Err(e) => {
+				println!("Failed to connect: {}", e);
+			}
+		}
+	}
+
+	/*
+	 * Discover available CXL switches
+	 */
+	pub fn discover_cxl_switches(options: &ArgMatches, env: &CxlFmOptions) {
+		if env.is_debug {
+			println!("{}", crate::CXL_FM_DISCOVER_SWITCHES_COMMAND_DESCRIPTOR);
+		}
+
+		if options.args_present() {
+			/*
+			 * Ignore currently.
+			 * Add code later.
+			 */
+		}
+
+		match TcpStream::connect(&env.ip_port) {
+			Ok(mut stream) => {
+				if env.is_debug {
+					println!("Successfully connected to server: {}",
+						 env.ip_port);
+				}
+
+				send_command(&mut stream,
+					     CXL_FM_DISCOVER_CXL_SWITCH_COMMAND,
+					     &env);
+			},
+			Err(e) => {
+				println!("Failed to connect: {}", e);
+			}
+		}
+	}
+
+	/*
+	 * Discover available logical devices
+	 */
+	pub fn discover_logical_devices(options: &ArgMatches, env: &CxlFmOptions) {
+		if env.is_debug {
+			println!("{}", crate::CXL_FM_DISCOVER_LOGICAL_DEVICES_COMMAND_DESCRIPTOR);
+		}
+
+		if options.args_present() {
+			/*
+			 * Ignore currently.
+			 * Add code later.
+			 */
+		}
+
+		match TcpStream::connect(&env.ip_port) {
+			Ok(mut stream) => {
+				if env.is_debug {
+					println!("Successfully connected to server: {}",
+						 env.ip_port);
+				}
+
+				send_command(&mut stream,
+					     CXL_FM_DISCOVER_LD_COMMAND,
+					     &env);
+			},
+			Err(e) => {
+				println!("Failed to connect: {}", e);
+			}
+		}
+	}
+}
diff --git a/fm_cli/src/dynamic_capacity_device.rs b/fm_cli/src/dynamic_capacity_device.rs
new file mode 100644
index 0000000..db4692f
--- /dev/null
+++ b/fm_cli/src/dynamic_capacity_device.rs
@@ -0,0 +1,225 @@ 
+/*
+ * CXL FM Infrastructure -- CXl Fabric Manager (FM) Infrastructure.
+ *
+ * CXL FM configuration tool implementation.
+ *
+ * Copyright (c) 2023 Viacheslav Dubeyko <slava@dubeyko.com>,
+ * All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+pub mod cxl_dcd_command {
+	use clap::{ArgMatches};
+	use std::net::{TcpStream};
+	use fm_library::cxl_fm_lib::CxlFmOptions;
+	use fm_library::cxl_fm_lib::send_command;
+	use fm_library::cxl_fm_lib::CXL_FM_DCD_GET_INFO_COMMAND;
+	use fm_library::cxl_fm_lib::CXL_FM_DCD_GET_CONFIG_COMMAND;
+	use fm_library::cxl_fm_lib::CXL_FM_DCD_SET_CONFIG_COMMAND;
+	use fm_library::cxl_fm_lib::CXL_FM_DCD_GET_EXTENT_COMMAND;
+	use fm_library::cxl_fm_lib::CXL_FM_DCD_ADD_CAPACITY_COMMAND;
+	use fm_library::cxl_fm_lib::CXL_FM_DCD_RELEASE_CAPACITY_COMMAND;
+
+	/*
+	 * Get Dynamic Capacity Device (DCD) info
+	 */
+	pub fn get_info(options: &ArgMatches, env: &CxlFmOptions) {
+		if env.is_debug {
+			println!("{}", crate::CXL_FM_DCD_GET_INFO_COMMAND_DESCRIPTOR);
+		}
+
+		if options.args_present() {
+			/*
+			 * Ignore currently.
+			 * Add code later.
+			 */
+		}
+
+		match TcpStream::connect(&env.ip_port) {
+			Ok(mut stream) => {
+				if env.is_debug {
+					println!("Successfully connected to server: {}",
+						 env.ip_port);
+				}
+
+				send_command(&mut stream,
+					     CXL_FM_DCD_GET_INFO_COMMAND,
+					     &env);
+			},
+			Err(e) => {
+				println!("Failed to connect: {}", e);
+			}
+		}
+	}
+
+	/*
+	 * Get dynamic capacity region configuration
+	 */
+	pub fn get_capacity_config(options: &ArgMatches, env: &CxlFmOptions) {
+		if env.is_debug {
+			println!("{}", crate::CXL_FM_DCD_GET_CONFIG_COMMAND_DESCRIPTOR);
+		}
+
+		if options.args_present() {
+			/*
+			 * Ignore currently.
+			 * Add code later.
+			 */
+		}
+
+		match TcpStream::connect(&env.ip_port) {
+			Ok(mut stream) => {
+				if env.is_debug {
+					println!("Successfully connected to server: {}",
+						 env.ip_port);
+				}
+
+				send_command(&mut stream,
+					     CXL_FM_DCD_GET_CONFIG_COMMAND,
+					     &env);
+			},
+			Err(e) => {
+				println!("Failed to connect: {}", e);
+			}
+		}
+	}
+
+	/*
+	 * Set dynamic capacity region configuration
+	 */
+	pub fn set_capacity_config(options: &ArgMatches, env: &CxlFmOptions) {
+		if env.is_debug {
+			println!("{}", crate::CXL_FM_DCD_SET_CONFIG_COMMAND_DESCRIPTOR);
+		}
+
+		if options.args_present() {
+			/*
+			 * Ignore currently.
+			 * Add code later.
+			 */
+		}
+
+		match TcpStream::connect(&env.ip_port) {
+			Ok(mut stream) => {
+				if env.is_debug {
+					println!("Successfully connected to server: {}",
+						 env.ip_port);
+				}
+
+				send_command(&mut stream,
+					     CXL_FM_DCD_SET_CONFIG_COMMAND,
+					     &env);
+			},
+			Err(e) => {
+				println!("Failed to connect: {}", e);
+			}
+		}
+	}
+
+	/*
+	 * Get Dynamic Capacity Device (DCD) extent list
+	 */
+	pub fn get_extent_list(options: &ArgMatches, env: &CxlFmOptions) {
+		if env.is_debug {
+			println!("{}", crate::CXL_FM_DCD_GET_EXTENT_COMMAND_DESCRIPTOR);
+		}
+
+		if options.args_present() {
+			/*
+			 * Ignore currently.
+			 * Add code later.
+			 */
+		}
+
+		match TcpStream::connect(&env.ip_port) {
+			Ok(mut stream) => {
+				if env.is_debug {
+					println!("Successfully connected to server: {}",
+						 env.ip_port);
+				}
+
+				send_command(&mut stream,
+					     CXL_FM_DCD_GET_EXTENT_COMMAND,
+					     &env);
+			},
+			Err(e) => {
+				println!("Failed to connect: {}", e);
+			}
+		}
+	}
+
+	/*
+	 * Initiate dynamic capacity add
+	 */
+	pub fn add_capacity(options: &ArgMatches, env: &CxlFmOptions) {
+		if env.is_debug {
+			println!("{}", crate::CXL_FM_DCD_ADD_CAPACITY_COMMAND_DESCRIPTOR);
+		}
+
+		if options.args_present() {
+			/*
+			 * Ignore currently.
+			 * Add code later.
+			 */
+		}
+
+		match TcpStream::connect(&env.ip_port) {
+			Ok(mut stream) => {
+				if env.is_debug {
+					println!("Successfully connected to server: {}",
+						 env.ip_port);
+				}
+
+				send_command(&mut stream,
+					     CXL_FM_DCD_ADD_CAPACITY_COMMAND,
+					     &env);
+			},
+			Err(e) => {
+				println!("Failed to connect: {}", e);
+			}
+		}
+	}
+
+	/*
+	 * Initiate dynamic capacity release
+	 */
+	pub fn release_capacity(options: &ArgMatches, env: &CxlFmOptions) {
+		if env.is_debug {
+			println!("{}", crate::CXL_FM_DCD_RELEASE_CAPACITY_COMMAND_DESCRIPTOR);
+		}
+
+		if options.args_present() {
+			/*
+			 * Ignore currently.
+			 * Add code later.
+			 */
+		}
+
+		match TcpStream::connect(&env.ip_port) {
+			Ok(mut stream) => {
+				if env.is_debug {
+					println!("Successfully connected to server: {}",
+						 env.ip_port);
+				}
+
+				send_command(&mut stream,
+					     CXL_FM_DCD_RELEASE_CAPACITY_COMMAND,
+					     &env);
+			},
+			Err(e) => {
+				println!("Failed to connect: {}", e);
+			}
+		}
+	}
+}
diff --git a/fm_cli/src/fm.rs b/fm_cli/src/fm.rs
new file mode 100644
index 0000000..c6ce77d
--- /dev/null
+++ b/fm_cli/src/fm.rs
@@ -0,0 +1,258 @@ 
+/*
+ * CXL FM Infrastructure -- CXl Fabric Manager (FM) Infrastructure.
+ *
+ * CXL FM configuration tool implementation.
+ *
+ * Copyright (c) 2023 Viacheslav Dubeyko <slava@dubeyko.com>,
+ * All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+pub mod cxl_fm_command {
+	use clap::{ArgMatches};
+	use std::net::{TcpStream};
+	use fm_library::cxl_fm_lib::CxlFmOptions;
+	use fm_library::cxl_fm_lib::send_command;
+	use fm_library::cxl_fm_lib::CXL_FM_GET_FM_INFO_COMMAND;
+	use fm_library::cxl_fm_lib::CXL_FM_START_FM_COMMAND;
+	use fm_library::cxl_fm_lib::CXL_FM_RESTART_FM_COMMAND;
+	use fm_library::cxl_fm_lib::CXL_FM_STOP_FM_COMMAND;
+	use fm_library::cxl_fm_lib::CXL_FM_GET_FM_CONFIG_COMMAND;
+	use fm_library::cxl_fm_lib::CXL_FM_SET_FM_CONFIG_COMMAND;
+	use fm_library::cxl_fm_lib::CXL_FM_GET_FM_EVENTS_COMMAND;
+
+	/*
+	 * Get Fabric Manager (FM) status/info
+	 */
+	pub fn get_info(options: &ArgMatches, env: &CxlFmOptions) {
+		if env.is_debug {
+			println!("{}", crate::CXL_FM_GET_INFO_COMMAND_DESCRIPTOR);
+		}
+
+		if options.args_present() {
+			/*
+			 * Ignore currently.
+			 * Add code later.
+			 */
+		}
+
+		match TcpStream::connect(&env.ip_port) {
+			Ok(mut stream) => {
+				if env.is_debug {
+					println!("Successfully connected to server: {}",
+						 env.ip_port);
+				}
+
+				send_command(&mut stream,
+					     CXL_FM_GET_FM_INFO_COMMAND,
+					     &env);
+			},
+			Err(e) => {
+				println!("Failed to connect: {}", e);
+			}
+		}
+	}
+
+	/*
+	 * Start Fabric Manager (FM) instance
+	 */
+	pub fn start(options: &ArgMatches, env: &CxlFmOptions) {
+		if env.is_debug {
+			println!("{}", crate::CXL_FM_START_COMMAND_DESCRIPTOR);
+		}
+
+		if options.args_present() {
+			/*
+			 * Ignore currently.
+			 * Add code later.
+			 */
+		}
+
+		match TcpStream::connect(&env.ip_port) {
+			Ok(mut stream) => {
+				if env.is_debug {
+					println!("Successfully connected to server: {}",
+						 env.ip_port);
+				}
+
+				send_command(&mut stream,
+					     CXL_FM_START_FM_COMMAND,
+					     &env);
+			},
+			Err(e) => {
+				println!("Failed to connect: {}", e);
+			}
+		}
+	}
+
+	/*
+	 * Restart Fabric Manager (FM) instance
+	 */
+	pub fn restart(options: &ArgMatches, env: &CxlFmOptions) {
+		if env.is_debug {
+			println!("{}", crate::CXL_FM_RESTART_COMMAND_DESCRIPTOR);
+		}
+
+		if options.args_present() {
+			/*
+			 * Ignore currently.
+			 * Add code later.
+			 */
+		}
+
+		match TcpStream::connect(&env.ip_port) {
+			Ok(mut stream) => {
+				if env.is_debug {
+					println!("Successfully connected to server: {}",
+						 env.ip_port);
+				}
+
+				send_command(&mut stream,
+					     CXL_FM_RESTART_FM_COMMAND,
+					     &env);
+			},
+			Err(e) => {
+				println!("Failed to connect: {}", e);
+			}
+		}
+	}
+
+	/*
+	 * Stop Fabric Manager (FM) instance
+	 */
+	pub fn stop(options: &ArgMatches, env: &CxlFmOptions) {
+		if env.is_debug {
+			println!("{}", crate::CXL_FM_STOP_COMMAND_DESCRIPTOR);
+		}
+
+		if options.args_present() {
+			/*
+			 * Ignore currently.
+			 * Add code later.
+			 */
+		}
+
+		match TcpStream::connect(&env.ip_port) {
+			Ok(mut stream) => {
+				if env.is_debug {
+					println!("Successfully connected to server: {}",
+						 env.ip_port);
+				}
+
+				send_command(&mut stream,
+					     CXL_FM_STOP_FM_COMMAND,
+					     &env);
+			},
+			Err(e) => {
+				println!("Failed to connect: {}", e);
+			}
+		}
+	}
+
+	/*
+	 * Get Fabric Manager (FM) configuration
+	 */
+	pub fn get_config(options: &ArgMatches, env: &CxlFmOptions) {
+		if env.is_debug {
+			println!("{}", crate::CXL_FM_GET_CONFIG_COMMAND_DESCRIPTOR);
+		}
+
+		if options.args_present() {
+			/*
+			 * Ignore currently.
+			 * Add code later.
+			 */
+		}
+
+		match TcpStream::connect(&env.ip_port) {
+			Ok(mut stream) => {
+				if env.is_debug {
+					println!("Successfully connected to server: {}",
+						 env.ip_port);
+				}
+
+				send_command(&mut stream,
+					     CXL_FM_GET_FM_CONFIG_COMMAND,
+					     &env);
+			},
+			Err(e) => {
+				println!("Failed to connect: {}", e);
+			}
+		}
+	}
+
+	/*
+	 * Set Fabric Manager (FM) configuration
+	 */
+	pub fn set_config(options: &ArgMatches, env: &CxlFmOptions) {
+		if env.is_debug {
+			println!("{}", crate::CXL_FM_SET_CONFIG_COMMAND_DESCRIPTOR);
+		}
+
+		if options.args_present() {
+			/*
+			 * Ignore currently.
+			 * Add code later.
+			 */
+		}
+
+		match TcpStream::connect(&env.ip_port) {
+			Ok(mut stream) => {
+				if env.is_debug {
+					println!("Successfully connected to server: {}",
+						 env.ip_port);
+				}
+
+				send_command(&mut stream,
+					     CXL_FM_SET_FM_CONFIG_COMMAND,
+					     &env);
+			},
+			Err(e) => {
+				println!("Failed to connect: {}", e);
+			}
+		}
+	}
+
+	/*
+	 * Get Fabric Manager (FM) event records
+	 */
+	pub fn get_events(options: &ArgMatches, env: &CxlFmOptions) {
+		if env.is_debug {
+			println!("{}", crate::CXL_FM_GET_EVENTS_COMMAND_DESCRIPTOR);
+		}
+
+		if options.args_present() {
+			/*
+			 * Ignore currently.
+			 * Add code later.
+			 */
+		}
+
+		match TcpStream::connect(&env.ip_port) {
+			Ok(mut stream) => {
+				if env.is_debug {
+					println!("Successfully connected to server: {}",
+						 env.ip_port);
+				}
+
+				send_command(&mut stream,
+					     CXL_FM_GET_FM_EVENTS_COMMAND,
+					     &env);
+			},
+			Err(e) => {
+				println!("Failed to connect: {}", e);
+			}
+		}
+	}
+}
diff --git a/fm_cli/src/logical_device.rs b/fm_cli/src/logical_device.rs
new file mode 100644
index 0000000..9ef7ddb
--- /dev/null
+++ b/fm_cli/src/logical_device.rs
@@ -0,0 +1,489 @@ 
+/*
+ * CXL FM Infrastructure -- CXl Fabric Manager (FM) Infrastructure.
+ *
+ * CXL FM configuration tool implementation.
+ *
+ * Copyright (c) 2023 Viacheslav Dubeyko <slava@dubeyko.com>,
+ * All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+pub mod cxl_logical_device_command {
+	use clap::{ArgMatches};
+	use std::net::{TcpStream};
+	use fm_library::cxl_fm_lib::CxlFmOptions;
+	use fm_library::cxl_fm_lib::send_command;
+	use fm_library::cxl_fm_lib::CXL_FM_BIND_LD_COMMAND;
+	use fm_library::cxl_fm_lib::CXL_FM_UNBIND_LD_COMMAND;
+	use fm_library::cxl_fm_lib::CXL_FM_CONNECT_MLD_COMMAND;
+	use fm_library::cxl_fm_lib::CXL_FM_DISCONNECT_MLD_COMMAND;
+	use fm_library::cxl_fm_lib::CXL_FM_GET_LD_ALLOCATION_COMMAND;
+	use fm_library::cxl_fm_lib::CXL_FM_SET_LD_ALLOCATION_COMMAND;
+	use fm_library::cxl_fm_lib::CXL_FM_GET_QOS_CONTROL_COMMAND;
+	use fm_library::cxl_fm_lib::CXL_FM_SET_QOS_CONTROL_COMMAND;
+	use fm_library::cxl_fm_lib::CXL_FM_GET_QOS_STATUS_COMMAND;
+	use fm_library::cxl_fm_lib::CXL_FM_GET_QOS_BANDWIDTH_COMMAND;
+	use fm_library::cxl_fm_lib::CXL_FM_SET_QOS_BANDWIDTH_COMMAND;
+	use fm_library::cxl_fm_lib::CXL_FM_GET_QOS_BANDWIDTH_LIMIT_COMMAND;
+	use fm_library::cxl_fm_lib::CXL_FM_SET_QOS_BANDWIDTH_LIMIT_COMMAND;
+	use fm_library::cxl_fm_lib::CXL_FM_LD_ERASE;
+
+	/*
+	 * Bind Logical Device (LD)
+	 */
+	pub fn bind(options: &ArgMatches, env: &CxlFmOptions) {
+		if env.is_debug {
+			println!("{}", crate::CXL_FM_LOGICAL_DEVICE_BIND_COMMAND_DESCRIPTOR);
+		}
+
+		if options.args_present() {
+			/*
+			 * Ignore currently.
+			 * Add code later.
+			 */
+		}
+
+		match TcpStream::connect(&env.ip_port) {
+			Ok(mut stream) => {
+				if env.is_debug {
+					println!("Successfully connected to server: {}",
+						 env.ip_port);
+				}
+
+				send_command(&mut stream,
+					     CXL_FM_BIND_LD_COMMAND,
+					     &env);
+			},
+			Err(e) => {
+				println!("Failed to connect: {}", e);
+			}
+		}
+	}
+
+	/*
+	 * Unbind Logical Device (LD)
+	 */
+	pub fn unbind(options: &ArgMatches, env: &CxlFmOptions) {
+		if env.is_debug {
+			println!("{}", crate::CXL_FM_LOGICAL_DEVICE_UNBIND_COMMAND_DESCRIPTOR);
+		}
+
+		if options.args_present() {
+			/*
+			 * Ignore currently.
+			 * Add code later.
+			 */
+		}
+
+		match TcpStream::connect(&env.ip_port) {
+			Ok(mut stream) => {
+				if env.is_debug {
+					println!("Successfully connected to server: {}",
+						 env.ip_port);
+				}
+
+				send_command(&mut stream,
+					     CXL_FM_UNBIND_LD_COMMAND,
+					     &env);
+			},
+			Err(e) => {
+				println!("Failed to connect: {}", e);
+			}
+		}
+	}
+
+	/*
+	 * Connect Multi Logical Device (MLD) to CXL switch
+	 */
+	pub fn connect(options: &ArgMatches, env: &CxlFmOptions) {
+		if env.is_debug {
+			println!("{}", crate::CXL_FM_LOGICAL_DEVICE_CONNECT_COMMAND_DESCRIPTOR);
+		}
+
+		if options.args_present() {
+			/*
+			 * Ignore currently.
+			 * Add code later.
+			 */
+		}
+
+		match TcpStream::connect(&env.ip_port) {
+			Ok(mut stream) => {
+				if env.is_debug {
+					println!("Successfully connected to server: {}",
+						 env.ip_port);
+				}
+
+				send_command(&mut stream,
+					     CXL_FM_CONNECT_MLD_COMMAND,
+					     &env);
+			},
+			Err(e) => {
+				println!("Failed to connect: {}", e);
+			}
+		}
+	}
+
+	/*
+	 * Disconnect Multi Logical Device (MLD) from CXL switch
+	 */
+	pub fn disconnect(options: &ArgMatches, env: &CxlFmOptions) {
+		if env.is_debug {
+			println!("{}", crate::CXL_FM_LOGICAL_DEVICE_DISCONNECT_COMMAND_DESCRIPTOR);
+		}
+
+		if options.args_present() {
+			/*
+			 * Ignore currently.
+			 * Add code later.
+			 */
+		}
+
+		match TcpStream::connect(&env.ip_port) {
+			Ok(mut stream) => {
+				if env.is_debug {
+					println!("Successfully connected to server: {}",
+						 env.ip_port);
+				}
+
+				send_command(&mut stream,
+					     CXL_FM_DISCONNECT_MLD_COMMAND,
+					     &env);
+			},
+			Err(e) => {
+				println!("Failed to connect: {}", e);
+			}
+		}
+	}
+
+	/*
+	 * Get Logical Device (LD) allocations
+	 */
+	pub fn get_allocation(options: &ArgMatches, env: &CxlFmOptions) {
+		if env.is_debug {
+			println!("{}", crate::CXL_FM_LOGICAL_DEVICE_GET_ALLOCATION_COMMAND_DESCRIPTOR);
+		}
+
+		if options.args_present() {
+			/*
+			 * Ignore currently.
+			 * Add code later.
+			 */
+		}
+
+		match TcpStream::connect(&env.ip_port) {
+			Ok(mut stream) => {
+				if env.is_debug {
+					println!("Successfully connected to server: {}",
+						 env.ip_port);
+				}
+
+				send_command(&mut stream,
+					     CXL_FM_GET_LD_ALLOCATION_COMMAND,
+					     &env);
+			},
+			Err(e) => {
+				println!("Failed to connect: {}", e);
+			}
+		}
+	}
+
+	/*
+	 * Set Logical Device (LD) allocations
+	 */
+	pub fn set_allocation(options: &ArgMatches, env: &CxlFmOptions) {
+		if env.is_debug {
+			println!("{}", crate::CXL_FM_LOGICAL_DEVICE_SET_ALLOCATION_COMMAND_DESCRIPTOR);
+		}
+
+		if options.args_present() {
+			/*
+			 * Ignore currently.
+			 * Add code later.
+			 */
+		}
+
+		match TcpStream::connect(&env.ip_port) {
+			Ok(mut stream) => {
+				if env.is_debug {
+					println!("Successfully connected to server: {}",
+						 env.ip_port);
+				}
+
+				send_command(&mut stream,
+					     CXL_FM_SET_LD_ALLOCATION_COMMAND,
+					     &env);
+			},
+			Err(e) => {
+				println!("Failed to connect: {}", e);
+			}
+		}
+	}
+
+	/*
+	 * Get QoS control
+	 */
+	pub fn get_qos_control(options: &ArgMatches, env: &CxlFmOptions) {
+		if env.is_debug {
+			println!("{}", crate::CXL_FM_LOGICAL_DEVICE_GET_QOS_CONTROL_COMMAND_DESCRIPTOR);
+		}
+
+		if options.args_present() {
+			/*
+			 * Ignore currently.
+			 * Add code later.
+			 */
+		}
+
+		match TcpStream::connect(&env.ip_port) {
+			Ok(mut stream) => {
+				if env.is_debug {
+					println!("Successfully connected to server: {}",
+						 env.ip_port);
+				}
+
+				send_command(&mut stream,
+					     CXL_FM_GET_QOS_CONTROL_COMMAND,
+					     &env);
+			},
+			Err(e) => {
+				println!("Failed to connect: {}", e);
+			}
+		}
+	}
+
+	/*
+	 * Set QoS control
+	 */
+	pub fn set_qos_control(options: &ArgMatches, env: &CxlFmOptions) {
+		if env.is_debug {
+			println!("{}", crate::CXL_FM_LOGICAL_DEVICE_SET_QOS_CONTROL_COMMAND_DESCRIPTOR);
+		}
+
+		if options.args_present() {
+			/*
+			 * Ignore currently.
+			 * Add code later.
+			 */
+		}
+
+		match TcpStream::connect(&env.ip_port) {
+			Ok(mut stream) => {
+				if env.is_debug {
+					println!("Successfully connected to server: {}",
+						 env.ip_port);
+				}
+
+				send_command(&mut stream,
+					     CXL_FM_SET_QOS_CONTROL_COMMAND,
+					     &env);
+			},
+			Err(e) => {
+				println!("Failed to connect: {}", e);
+			}
+		}
+	}
+
+	/*
+	 * Get QoS status
+	 */
+	pub fn get_qos_status(options: &ArgMatches, env: &CxlFmOptions) {
+		if env.is_debug {
+			println!("{}", crate::CXL_FM_LOGICAL_DEVICE_GET_QOS_STATUS_COMMAND_DESCRIPTOR);
+		}
+
+		if options.args_present() {
+			/*
+			 * Ignore currently.
+			 * Add code later.
+			 */
+		}
+
+		match TcpStream::connect(&env.ip_port) {
+			Ok(mut stream) => {
+				if env.is_debug {
+					println!("Successfully connected to server: {}",
+						 env.ip_port);
+				}
+
+				send_command(&mut stream,
+					     CXL_FM_GET_QOS_STATUS_COMMAND,
+					     &env);
+			},
+			Err(e) => {
+				println!("Failed to connect: {}", e);
+			}
+		}
+	}
+
+	/*
+	 * Get QoS allocated bandwidth
+	 */
+	pub fn get_qos_bandwidth(options: &ArgMatches, env: &CxlFmOptions) {
+		if env.is_debug {
+			println!("{}", crate::CXL_FM_LOGICAL_DEVICE_GET_QOS_BANDWIDTH_COMMAND_DESCRIPTOR);
+		}
+
+		if options.args_present() {
+			/*
+			 * Ignore currently.
+			 * Add code later.
+			 */
+		}
+
+		match TcpStream::connect(&env.ip_port) {
+			Ok(mut stream) => {
+				if env.is_debug {
+					println!("Successfully connected to server: {}",
+						 env.ip_port);
+				}
+
+				send_command(&mut stream,
+					     CXL_FM_GET_QOS_BANDWIDTH_COMMAND,
+					     &env);
+			},
+			Err(e) => {
+				println!("Failed to connect: {}", e);
+			}
+		}
+	}
+
+	/*
+	 * Set QoS allocated bandwidth
+	 */
+	pub fn set_qos_bandwidth(options: &ArgMatches, env: &CxlFmOptions) {
+		if env.is_debug {
+			println!("{}", crate::CXL_FM_LOGICAL_DEVICE_SET_QOS_BANDWIDTH_COMMAND_DESCRIPTOR);
+		}
+
+		if options.args_present() {
+			/*
+			 * Ignore currently.
+			 * Add code later.
+			 */
+		}
+
+		match TcpStream::connect(&env.ip_port) {
+			Ok(mut stream) => {
+				if env.is_debug {
+					println!("Successfully connected to server: {}",
+						 env.ip_port);
+				}
+
+				send_command(&mut stream,
+					     CXL_FM_SET_QOS_BANDWIDTH_COMMAND,
+					     &env);
+			},
+			Err(e) => {
+				println!("Failed to connect: {}", e);
+			}
+		}
+	}
+
+	/*
+	 * Get QoS bandwidth limit
+	 */
+	pub fn get_qos_bandwidth_limit(options: &ArgMatches, env: &CxlFmOptions) {
+		if env.is_debug {
+			println!("{}", crate::CXL_FM_LOGICAL_DEVICE_GET_QOS_BANDWIDTH_LIMIT_COMMAND_DESCRIPTOR);
+		}
+
+		if options.args_present() {
+			/*
+			 * Ignore currently.
+			 * Add code later.
+			 */
+		}
+
+		match TcpStream::connect(&env.ip_port) {
+			Ok(mut stream) => {
+				if env.is_debug {
+					println!("Successfully connected to server: {}",
+						 env.ip_port);
+				}
+
+				send_command(&mut stream,
+					     CXL_FM_GET_QOS_BANDWIDTH_LIMIT_COMMAND,
+					     &env);
+			},
+			Err(e) => {
+				println!("Failed to connect: {}", e);
+			}
+		}
+	}
+
+	/*
+	 * Set QoS bandwidth limit
+	 */
+	pub fn set_qos_bandwidth_limit(options: &ArgMatches, env: &CxlFmOptions) {
+		if env.is_debug {
+			println!("{}", crate::CXL_FM_LOGICAL_DEVICE_SET_QOS_BANDWIDTH_LIMIT_COMMAND_DESCRIPTOR);
+		}
+
+		if options.args_present() {
+			/*
+			 * Ignore currently.
+			 * Add code later.
+			 */
+		}
+
+		match TcpStream::connect(&env.ip_port) {
+			Ok(mut stream) => {
+				if env.is_debug {
+					println!("Successfully connected to server: {}",
+						 env.ip_port);
+				}
+
+				send_command(&mut stream,
+					     CXL_FM_SET_QOS_BANDWIDTH_LIMIT_COMMAND,
+					     &env);
+			},
+			Err(e) => {
+				println!("Failed to connect: {}", e);
+			}
+		}
+	}
+
+	/*
+	 * Secure erase after unbinding
+	 */
+	pub fn erase(options: &ArgMatches, env: &CxlFmOptions) {
+		if env.is_debug {
+			println!("{}", crate::CXL_FM_LOGICAL_DEVICE_ERASE_COMMAND_DESCRIPTOR);
+		}
+
+		if options.args_present() {
+			/*
+			 * Ignore currently.
+			 * Add code later.
+			 */
+		}
+
+		match TcpStream::connect(&env.ip_port) {
+			Ok(mut stream) => {
+				if env.is_debug {
+					println!("Successfully connected to server: {}",
+						 env.ip_port);
+				}
+
+				send_command(&mut stream,
+					     CXL_FM_LD_ERASE,
+					     &env);
+			},
+			Err(e) => {
+				println!("Failed to connect: {}", e);
+			}
+		}
+	}
+}
diff --git a/fm_cli/src/main.rs b/fm_cli/src/main.rs
new file mode 100644
index 0000000..b580a84
--- /dev/null
+++ b/fm_cli/src/main.rs
@@ -0,0 +1,721 @@ 
+/*
+ * CXL FM Infrastructure -- CXl Fabric Manager (FM) Infrastructure.
+ *
+ * CXL FM configuration tool implementation.
+ *
+ * Copyright (c) 2023 Viacheslav Dubeyko <slava@dubeyko.com>,
+ * All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+mod discover;
+mod fm;
+mod switch;
+mod multi_headed_device;
+mod logical_device;
+mod pci2pci_bridge;
+mod physical_port;
+mod mld_port;
+mod dynamic_capacity_device;
+
+use clap::{Arg, Command};
+pub use crate::discover::cxl_fm_discover_command;
+pub use crate::fm::cxl_fm_command;
+pub use crate::switch::cxl_switch_command;
+pub use crate::multi_headed_device::cxl_mh_device_command;
+pub use crate::logical_device::cxl_logical_device_command;
+pub use crate::pci2pci_bridge::cxl_ppb_command;
+pub use crate::physical_port::cxl_physical_port_command;
+pub use crate::mld_port::cxl_mld_port_command;
+pub use crate::dynamic_capacity_device::cxl_dcd_command;
+pub use fm_library::cxl_fm_lib::CxlFmOptions;
+
+/*
+ * CXL FM configuration tool version
+ */
+const CXL_FM_TOOL_VERSION: &str = "0.0.1";
+
+/*
+ * CXL FM configuration tool strings
+ */
+const CXL_FM_TOOL_NAME: &str = "fm_cli";
+const CXL_FM_TOOL_DESCRIPTOR: &str = "CXL Fabric Manager (FM) CLI";
+const CXL_FM_TOOL_DEBUG_OPTION: &str = "debug";
+const CXL_FM_TOOL_DEBUG_OPTION_SHORT: char = 'd';
+const CXL_FM_TOOL_IP_ADDRESS_OPTION: &str = "ip";
+const CXL_FM_TOOL_IP_ADDRESS_OPTION_SHORT: char = 'i';
+const CXL_FM_TOOL_PORT_OPTION: &str = "port";
+const CXL_FM_TOOL_PORT_OPTION_SHORT: char = 'p';
+
+/*
+ * Discover command strings
+ */
+const CXL_FM_DISCOVER_COMMAND: &str = "discover";
+const CXL_FM_DISCOVER_COMMAND_DESCRIPTOR: &str = "Discover available CXL agents";
+const CXL_FM_DISCOVER_FM_COMMAND: &str = "fm";
+const CXL_FM_DISCOVER_FM_COMMAND_DESCRIPTOR: &str = "Discover FM instances";
+const CXL_FM_DISCOVER_DEVICES_COMMAND: &str = "cxl_devices";
+const CXL_FM_DISCOVER_DEVICES_COMMAND_DESCRIPTOR: &str = "Discover CXL devices";
+const CXL_FM_DISCOVER_SWITCHES_COMMAND: &str = "cxl_switch";
+const CXL_FM_DISCOVER_SWITCHES_COMMAND_DESCRIPTOR: &str = "Discover CXL switches";
+const CXL_FM_DISCOVER_LOGICAL_DEVICES_COMMAND: &str = "logical_devices";
+const CXL_FM_DISCOVER_LOGICAL_DEVICES_COMMAND_DESCRIPTOR: &str = "Discover logical devices";
+
+/*
+ * FM command strings
+ */
+const CXL_FM_COMMAND: &str = "fm";
+const CXL_FM_COMMAND_DESCRIPTOR: &str = "Manage Fabric Manager (FM)";
+const CXL_FM_GET_INFO_COMMAND: &str = "get_info";
+const CXL_FM_GET_INFO_COMMAND_DESCRIPTOR: &str = "Get Fabric Manager (FM) status/info";
+const CXL_FM_START_COMMAND: &str = "start";
+const CXL_FM_START_COMMAND_DESCRIPTOR: &str = "Start Fabric Manager (FM) instance";
+const CXL_FM_RESTART_COMMAND: &str = "restart";
+const CXL_FM_RESTART_COMMAND_DESCRIPTOR: &str = "Restart Fabric Manager (FM) instance";
+const CXL_FM_STOP_COMMAND: &str = "stop";
+const CXL_FM_STOP_COMMAND_DESCRIPTOR: &str = "Stop Fabric Manager (FM) instance";
+const CXL_FM_GET_CONFIG_COMMAND: &str = "get_config";
+const CXL_FM_GET_CONFIG_COMMAND_DESCRIPTOR: &str = "Get Fabric Manager (FM) configuration";
+const CXL_FM_SET_CONFIG_COMMAND: &str = "set_config";
+const CXL_FM_SET_CONFIG_COMMAND_DESCRIPTOR: &str = "Set Fabric Manager (FM) configuration";
+const CXL_FM_GET_EVENTS_COMMAND: &str = "get_events";
+const CXL_FM_GET_EVENTS_COMMAND_DESCRIPTOR: &str = "Get Fabric Manager (FM) event records";
+
+/*
+ * Switch command strings
+ */
+const CXL_FM_SWITCH_COMMAND: &str = "switch";
+const CXL_FM_SWITCH_COMMAND_DESCRIPTOR: &str = "Manage CXL switch";
+const CXL_FM_SWITCH_GET_INFO_COMMAND: &str = "get_info";
+const CXL_FM_SWITCH_GET_INFO_COMMAND_DESCRIPTOR: &str = "Get CXL switch status/info";
+const CXL_FM_SWITCH_GET_CONFIG_COMMAND: &str = "get_config";
+const CXL_FM_SWITCH_GET_CONFIG_COMMAND_DESCRIPTOR: &str = "Get CXL switch configuration";
+const CXL_FM_SWITCH_SET_CONFIG_COMMAND: &str = "set_config";
+const CXL_FM_SWITCH_SET_CONFIG_COMMAND_DESCRIPTOR: &str = "Set CXL switch configuration";
+
+/*
+ * Multi Headed Device (MHD) command strings
+ */
+const CXL_FM_MH_DEVICE_COMMAND: &str = "mh_device";
+const CXL_FM_MH_DEVICE_COMMAND_DESCRIPTOR: &str = "Manage Multi Headed Device (MHD)";
+const CXL_FM_MH_DEVICE_GET_INFO_COMMAND: &str = "get_info";
+const CXL_FM_MH_DEVICE_GET_INFO_COMMAND_DESCRIPTOR: &str = "Get Multi Headed Device (MHD) status/info";
+
+/*
+ * Logical Device (LD) command strings
+ */
+const CXL_FM_LOGICAL_DEVICE_COMMAND: &str = "logical_device";
+const CXL_FM_LOGICAL_DEVICE_COMMAND_DESCRIPTOR: &str = "Manage Logical Device (LD)";
+const CXL_FM_LOGICAL_DEVICE_BIND_COMMAND: &str = "bind";
+const CXL_FM_LOGICAL_DEVICE_BIND_COMMAND_DESCRIPTOR: &str = "Bind Logical Device (LD)";
+const CXL_FM_LOGICAL_DEVICE_UNBIND_COMMAND: &str = "unbind";
+const CXL_FM_LOGICAL_DEVICE_UNBIND_COMMAND_DESCRIPTOR: &str = "Unbind Logical Device (LD)";
+const CXL_FM_LOGICAL_DEVICE_CONNECT_COMMAND: &str = "connect";
+const CXL_FM_LOGICAL_DEVICE_CONNECT_COMMAND_DESCRIPTOR: &str = "Connect Multi Logical Device (MLD) to CXL switch";
+const CXL_FM_LOGICAL_DEVICE_DISCONNECT_COMMAND: &str = "disconnect";
+const CXL_FM_LOGICAL_DEVICE_DISCONNECT_COMMAND_DESCRIPTOR: &str = "Disconnect Multi Logical Device (MLD) from CXL switch";
+const CXL_FM_LOGICAL_DEVICE_GET_ALLOCATION_COMMAND: &str = "get_allocation";
+const CXL_FM_LOGICAL_DEVICE_GET_ALLOCATION_COMMAND_DESCRIPTOR: &str = "Get Logical Device (LD) allocations";
+const CXL_FM_LOGICAL_DEVICE_SET_ALLOCATION_COMMAND: &str = "set_allocation";
+const CXL_FM_LOGICAL_DEVICE_SET_ALLOCATION_COMMAND_DESCRIPTOR: &str = "Set Logical Device (LD) allocations";
+const CXL_FM_LOGICAL_DEVICE_GET_QOS_CONTROL_COMMAND: &str = "get_qos_control";
+const CXL_FM_LOGICAL_DEVICE_GET_QOS_CONTROL_COMMAND_DESCRIPTOR: &str = "Get QoS control";
+const CXL_FM_LOGICAL_DEVICE_SET_QOS_CONTROL_COMMAND: &str = "set_qos_control";
+const CXL_FM_LOGICAL_DEVICE_SET_QOS_CONTROL_COMMAND_DESCRIPTOR: &str = "Set QoS control";
+const CXL_FM_LOGICAL_DEVICE_GET_QOS_STATUS_COMMAND: &str = "get_qos_status";
+const CXL_FM_LOGICAL_DEVICE_GET_QOS_STATUS_COMMAND_DESCRIPTOR: &str = "Get QoS status";
+const CXL_FM_LOGICAL_DEVICE_GET_QOS_BANDWIDTH_COMMAND: &str = "get_qos_allocated_bandwidth";
+const CXL_FM_LOGICAL_DEVICE_GET_QOS_BANDWIDTH_COMMAND_DESCRIPTOR: &str = "Get QoS allocated bandwidth";
+const CXL_FM_LOGICAL_DEVICE_SET_QOS_BANDWIDTH_COMMAND: &str = "set_qos_allocated_bandwidth";
+const CXL_FM_LOGICAL_DEVICE_SET_QOS_BANDWIDTH_COMMAND_DESCRIPTOR: &str = "Set QoS allocated bandwidth";
+const CXL_FM_LOGICAL_DEVICE_GET_QOS_BANDWIDTH_LIMIT_COMMAND: &str = "get_qos_bandwidth_limit";
+const CXL_FM_LOGICAL_DEVICE_GET_QOS_BANDWIDTH_LIMIT_COMMAND_DESCRIPTOR: &str = "Get QoS bandwidth limit";
+const CXL_FM_LOGICAL_DEVICE_SET_QOS_BANDWIDTH_LIMIT_COMMAND: &str = "set_qos_bandwidth_limit";
+const CXL_FM_LOGICAL_DEVICE_SET_QOS_BANDWIDTH_LIMIT_COMMAND_DESCRIPTOR: &str = "Set QoS bandwidth limit";
+const CXL_FM_LOGICAL_DEVICE_ERASE_COMMAND: &str = "erase";
+const CXL_FM_LOGICAL_DEVICE_ERASE_COMMAND_DESCRIPTOR: &str = "Secure erase after unbinding";
+
+/*
+ * PCI-to-PCI Bridge (PPB) command strings
+ */
+const CXL_FM_PPB_COMMAND: &str = "ppb";
+const CXL_FM_PPB_COMMAND_DESCRIPTOR: &str = "Manage PCI-to-PCI Bridge (PPB)";
+const CXL_FM_PPB_CONFIG_COMMAND: &str = "config";
+const CXL_FM_PPB_CONFIG_COMMAND_DESCRIPTOR: &str = "Send PCI-to-PCI Bridge (PPB) configuration request";
+const CXL_FM_PPB_BIND_COMMAND: &str = "bind";
+const CXL_FM_PPB_BIND_COMMAND_DESCRIPTOR: &str = "Bind Virtual PCI-to-PCI Bridge (vPPB) inside a CXL switch";
+const CXL_FM_PPB_UNBIND_COMMAND: &str = "unbind";
+const CXL_FM_PPB_UNBIND_COMMAND_DESCRIPTOR: &str = "Unbind Virtual PCI-to-PCI Bridge (vPPB) inside a CXL switch";
+
+/*
+ * Physical port command strings
+ */
+const CXL_FM_PHYSICAL_PORT_COMMAND: &str = "physical_port";
+const CXL_FM_PHYSICAL_PORT_COMMAND_DESCRIPTOR: &str = "Manage physical ports";
+const CXL_FM_PHYSICAL_PORT_GET_INFO_COMMAND: &str = "get_info";
+const CXL_FM_PHYSICAL_PORT_GET_INFO_COMMAND_DESCRIPTOR: &str = "Get state of physical port";
+const CXL_FM_PHYSICAL_PORT_CONTROL_COMMAND: &str = "control";
+const CXL_FM_PHYSICAL_PORT_CONTROL_COMMAND_DESCRIPTOR: &str = "Control physical port";
+const CXL_FM_PHYSICAL_PORT_BIND_COMMAND: &str = "bind";
+const CXL_FM_PHYSICAL_PORT_BIND_COMMAND_DESCRIPTOR: &str = "Bind physical port to Virtual PCI-to-PCI Bridge (vPPB)";
+const CXL_FM_PHYSICAL_PORT_UNBIND_COMMAND: &str = "unbind";
+const CXL_FM_PHYSICAL_PORT_UNBIND_COMMAND_DESCRIPTOR: &str = "Unbind physical port from Virtual PCI-to-PCI Bridge (vPPB)";
+
+/*
+ * Multi-Logical Device (MLD) ports command strings
+ */
+const CXL_FM_MLD_PORT_COMMAND: &str = "mld_port";
+const CXL_FM_MLD_PORT_COMMAND_DESCRIPTOR: &str = "Manage Multi-Logical Device (MLD) ports";
+const CXL_FM_MLD_PORT_TUNNEL_COMMAND: &str = "tunnel";
+const CXL_FM_MLD_PORT_TUNNEL_COMMAND_DESCRIPTOR: &str = "Tunnel Management Command";
+const CXL_FM_MLD_PORT_SEND_CONFIG_COMMAND: &str = "send_config";
+const CXL_FM_MLD_PORT_SEND_CONFIG_COMMAND_DESCRIPTOR: &str = "Send CXL.io configuration request";
+const CXL_FM_MLD_PORT_SEND_MEM_REQUEST_COMMAND: &str = "send_memory_request";
+const CXL_FM_MLD_PORT_SEND_MEM_REQUEST_COMMAND_DESCRIPTOR: &str = "Send CXL.io memory request";
+
+/*
+ * Dynamic Capacity Device (DCD) command strings
+ */
+const CXL_FM_DCD_COMMAND: &str = "dcd";
+const CXL_FM_DCD_COMMAND_DESCRIPTOR: &str = "Manage Dynamic Capacity Device (DCD)";
+const CXL_FM_DCD_GET_INFO_COMMAND: &str = "get_info";
+const CXL_FM_DCD_GET_INFO_COMMAND_DESCRIPTOR: &str = "Get Dynamic Capacity Device (DCD) info";
+const CXL_FM_DCD_GET_CONFIG_COMMAND: &str = "get_capacity_config";
+const CXL_FM_DCD_GET_CONFIG_COMMAND_DESCRIPTOR: &str = "Get dynamic capacity region configuration";
+const CXL_FM_DCD_SET_CONFIG_COMMAND: &str = "set_capacity_config";
+const CXL_FM_DCD_SET_CONFIG_COMMAND_DESCRIPTOR: &str = "Set dynamic capacity region configuration";
+const CXL_FM_DCD_GET_EXTENT_COMMAND: &str = "get_extent_list";
+const CXL_FM_DCD_GET_EXTENT_COMMAND_DESCRIPTOR: &str = "Get Dynamic Capacity Device (DCD) extent list";
+const CXL_FM_DCD_ADD_CAPACITY_COMMAND: &str = "add_capacity";
+const CXL_FM_DCD_ADD_CAPACITY_COMMAND_DESCRIPTOR: &str = "Initiate dynamic capacity add";
+const CXL_FM_DCD_RELEASE_CAPACITY_COMMAND: &str = "release_capacity";
+const CXL_FM_DCD_RELEASE_CAPACITY_COMMAND_DESCRIPTOR: &str = "Initiate dynamic capacity release";
+
+/*
+ * Command line interface definition
+ */
+fn cli() -> Command {
+	Command::new(CXL_FM_TOOL_NAME)
+		.about(CXL_FM_TOOL_DESCRIPTOR)
+		.version(CXL_FM_TOOL_VERSION)
+		.subcommand_required(true)
+		.arg_required_else_help(true)
+		.allow_external_subcommands(true)
+		.arg(Arg::new(CXL_FM_TOOL_DEBUG_OPTION)
+			.short(CXL_FM_TOOL_DEBUG_OPTION_SHORT)
+			.long(CXL_FM_TOOL_DEBUG_OPTION)
+			.action(clap::ArgAction::SetTrue))
+		.arg(Arg::new(CXL_FM_TOOL_IP_ADDRESS_OPTION)
+			.short(CXL_FM_TOOL_IP_ADDRESS_OPTION_SHORT)
+			.long(CXL_FM_TOOL_IP_ADDRESS_OPTION)
+			.action(clap::ArgAction::Set)
+			.required(true))
+		.arg(Arg::new(CXL_FM_TOOL_PORT_OPTION)
+			.short(CXL_FM_TOOL_PORT_OPTION_SHORT)
+			.long(CXL_FM_TOOL_PORT_OPTION)
+			.action(clap::ArgAction::Set)
+			.required(true))
+		.subcommand(
+			Command::new(CXL_FM_DISCOVER_COMMAND)
+				.about(CXL_FM_DISCOVER_COMMAND_DESCRIPTOR)
+				.subcommand_required(true)
+				.arg_required_else_help(true)
+				.allow_external_subcommands(true)
+				.subcommand(
+					Command::new(CXL_FM_DISCOVER_FM_COMMAND)
+						.about(CXL_FM_DISCOVER_FM_COMMAND_DESCRIPTOR)
+				)
+				.subcommand(
+					Command::new(CXL_FM_DISCOVER_DEVICES_COMMAND)
+						.about(CXL_FM_DISCOVER_DEVICES_COMMAND_DESCRIPTOR)
+				)
+				.subcommand(
+					Command::new(CXL_FM_DISCOVER_SWITCHES_COMMAND)
+						.about(CXL_FM_DISCOVER_SWITCHES_COMMAND_DESCRIPTOR)
+				)
+				.subcommand(
+					Command::new(CXL_FM_DISCOVER_LOGICAL_DEVICES_COMMAND)
+						.about(CXL_FM_DISCOVER_LOGICAL_DEVICES_COMMAND_DESCRIPTOR)
+				)
+		)
+		.subcommand(
+			Command::new(CXL_FM_COMMAND)
+				.about(CXL_FM_COMMAND_DESCRIPTOR)
+				.subcommand_required(true)
+				.arg_required_else_help(true)
+				.allow_external_subcommands(true)
+				.subcommand(
+					Command::new(CXL_FM_GET_INFO_COMMAND)
+						.about(CXL_FM_GET_INFO_COMMAND_DESCRIPTOR)
+				)
+				.subcommand(
+					Command::new(CXL_FM_START_COMMAND)
+						.about(CXL_FM_START_COMMAND_DESCRIPTOR)
+				)
+				.subcommand(
+					Command::new(CXL_FM_RESTART_COMMAND)
+						.about(CXL_FM_RESTART_COMMAND_DESCRIPTOR)
+				)
+				.subcommand(
+					Command::new(CXL_FM_STOP_COMMAND)
+						.about(CXL_FM_STOP_COMMAND_DESCRIPTOR)
+				)
+				.subcommand(
+					Command::new(CXL_FM_GET_CONFIG_COMMAND)
+						.about(CXL_FM_GET_CONFIG_COMMAND_DESCRIPTOR)
+				)
+				.subcommand(
+					Command::new(CXL_FM_SET_CONFIG_COMMAND)
+						.about(CXL_FM_SET_CONFIG_COMMAND_DESCRIPTOR)
+				)
+				.subcommand(
+					Command::new(CXL_FM_GET_EVENTS_COMMAND)
+						.about(CXL_FM_GET_EVENTS_COMMAND_DESCRIPTOR)
+				)
+		)
+		.subcommand(
+			Command::new(CXL_FM_SWITCH_COMMAND)
+				.about(CXL_FM_SWITCH_COMMAND_DESCRIPTOR)
+				.subcommand_required(true)
+				.arg_required_else_help(true)
+				.allow_external_subcommands(true)
+				.subcommand(
+					Command::new(CXL_FM_SWITCH_GET_INFO_COMMAND)
+						.about(CXL_FM_SWITCH_GET_INFO_COMMAND_DESCRIPTOR)
+				)
+				.subcommand(
+					Command::new(CXL_FM_SWITCH_GET_CONFIG_COMMAND)
+						.about(CXL_FM_SWITCH_GET_CONFIG_COMMAND_DESCRIPTOR)
+				)
+				.subcommand(
+					Command::new(CXL_FM_SWITCH_SET_CONFIG_COMMAND)
+						.about(CXL_FM_SWITCH_SET_CONFIG_COMMAND_DESCRIPTOR)
+				)
+		)
+		.subcommand(
+			Command::new(CXL_FM_MH_DEVICE_COMMAND)
+				.about(CXL_FM_MH_DEVICE_COMMAND_DESCRIPTOR)
+				.subcommand_required(true)
+				.arg_required_else_help(true)
+				.allow_external_subcommands(true)
+				.subcommand(
+					Command::new(CXL_FM_MH_DEVICE_GET_INFO_COMMAND)
+						.about(CXL_FM_MH_DEVICE_GET_INFO_COMMAND_DESCRIPTOR)
+				)
+		)
+		.subcommand(
+			Command::new(CXL_FM_LOGICAL_DEVICE_COMMAND)
+				.about(CXL_FM_LOGICAL_DEVICE_COMMAND_DESCRIPTOR)
+				.subcommand_required(true)
+				.arg_required_else_help(true)
+				.allow_external_subcommands(true)
+				.subcommand(
+					Command::new(CXL_FM_LOGICAL_DEVICE_BIND_COMMAND)
+						.about(CXL_FM_LOGICAL_DEVICE_BIND_COMMAND_DESCRIPTOR)
+				)
+				.subcommand(
+					Command::new(CXL_FM_LOGICAL_DEVICE_UNBIND_COMMAND)
+						.about(CXL_FM_LOGICAL_DEVICE_UNBIND_COMMAND_DESCRIPTOR)
+				)
+				.subcommand(
+					Command::new(CXL_FM_LOGICAL_DEVICE_CONNECT_COMMAND)
+						.about(CXL_FM_LOGICAL_DEVICE_CONNECT_COMMAND_DESCRIPTOR)
+				)
+				.subcommand(
+					Command::new(CXL_FM_LOGICAL_DEVICE_DISCONNECT_COMMAND)
+						.about(CXL_FM_LOGICAL_DEVICE_DISCONNECT_COMMAND_DESCRIPTOR)
+				)
+				.subcommand(
+					Command::new(CXL_FM_LOGICAL_DEVICE_GET_ALLOCATION_COMMAND)
+						.about(CXL_FM_LOGICAL_DEVICE_GET_ALLOCATION_COMMAND_DESCRIPTOR)
+				)
+				.subcommand(
+					Command::new(CXL_FM_LOGICAL_DEVICE_SET_ALLOCATION_COMMAND)
+						.about(CXL_FM_LOGICAL_DEVICE_SET_ALLOCATION_COMMAND_DESCRIPTOR)
+				)
+				.subcommand(
+					Command::new(CXL_FM_LOGICAL_DEVICE_GET_QOS_CONTROL_COMMAND)
+						.about(CXL_FM_LOGICAL_DEVICE_GET_QOS_CONTROL_COMMAND_DESCRIPTOR)
+				)
+				.subcommand(
+					Command::new(CXL_FM_LOGICAL_DEVICE_SET_QOS_CONTROL_COMMAND)
+						.about(CXL_FM_LOGICAL_DEVICE_SET_QOS_CONTROL_COMMAND_DESCRIPTOR)
+				)
+				.subcommand(
+					Command::new(CXL_FM_LOGICAL_DEVICE_GET_QOS_STATUS_COMMAND)
+						.about(CXL_FM_LOGICAL_DEVICE_GET_QOS_STATUS_COMMAND_DESCRIPTOR)
+				)
+				.subcommand(
+					Command::new(CXL_FM_LOGICAL_DEVICE_GET_QOS_BANDWIDTH_COMMAND)
+						.about(CXL_FM_LOGICAL_DEVICE_GET_QOS_BANDWIDTH_COMMAND_DESCRIPTOR)
+				)
+				.subcommand(
+					Command::new(CXL_FM_LOGICAL_DEVICE_SET_QOS_BANDWIDTH_COMMAND)
+						.about(CXL_FM_LOGICAL_DEVICE_SET_QOS_BANDWIDTH_COMMAND_DESCRIPTOR)
+				)
+				.subcommand(
+					Command::new(CXL_FM_LOGICAL_DEVICE_GET_QOS_BANDWIDTH_LIMIT_COMMAND)
+						.about(CXL_FM_LOGICAL_DEVICE_GET_QOS_BANDWIDTH_LIMIT_COMMAND_DESCRIPTOR)
+				)
+				.subcommand(
+					Command::new(CXL_FM_LOGICAL_DEVICE_SET_QOS_BANDWIDTH_LIMIT_COMMAND)
+						.about(CXL_FM_LOGICAL_DEVICE_SET_QOS_BANDWIDTH_LIMIT_COMMAND_DESCRIPTOR)
+				)
+				.subcommand(
+					Command::new(CXL_FM_LOGICAL_DEVICE_ERASE_COMMAND)
+						.about(CXL_FM_LOGICAL_DEVICE_ERASE_COMMAND_DESCRIPTOR)
+				)
+		)
+		.subcommand(
+			Command::new(CXL_FM_PPB_COMMAND)
+				.about(CXL_FM_PPB_COMMAND_DESCRIPTOR)
+				.subcommand_required(true)
+				.arg_required_else_help(true)
+				.allow_external_subcommands(true)
+				.subcommand(
+					Command::new(CXL_FM_PPB_CONFIG_COMMAND)
+						.about(CXL_FM_PPB_CONFIG_COMMAND_DESCRIPTOR)
+				)
+				.subcommand(
+					Command::new(CXL_FM_PPB_BIND_COMMAND)
+						.about(CXL_FM_PPB_BIND_COMMAND_DESCRIPTOR)
+				)
+				.subcommand(
+					Command::new(CXL_FM_PPB_UNBIND_COMMAND)
+						.about(CXL_FM_PPB_UNBIND_COMMAND_DESCRIPTOR)
+				)
+		)
+		.subcommand(
+			Command::new(CXL_FM_PHYSICAL_PORT_COMMAND)
+				.about(CXL_FM_PHYSICAL_PORT_COMMAND_DESCRIPTOR)
+				.subcommand_required(true)
+				.arg_required_else_help(true)
+				.allow_external_subcommands(true)
+				.subcommand(
+					Command::new(CXL_FM_PHYSICAL_PORT_GET_INFO_COMMAND)
+						.about(CXL_FM_PHYSICAL_PORT_GET_INFO_COMMAND_DESCRIPTOR)
+				)
+				.subcommand(
+					Command::new(CXL_FM_PHYSICAL_PORT_CONTROL_COMMAND)
+						.about(CXL_FM_PHYSICAL_PORT_CONTROL_COMMAND_DESCRIPTOR)
+				)
+				.subcommand(
+					Command::new(CXL_FM_PHYSICAL_PORT_BIND_COMMAND)
+						.about(CXL_FM_PHYSICAL_PORT_BIND_COMMAND_DESCRIPTOR)
+				)
+				.subcommand(
+					Command::new(CXL_FM_PHYSICAL_PORT_UNBIND_COMMAND)
+						.about(CXL_FM_PHYSICAL_PORT_UNBIND_COMMAND_DESCRIPTOR)
+				)
+		)
+		.subcommand(
+			Command::new(CXL_FM_MLD_PORT_COMMAND)
+				.about(CXL_FM_MLD_PORT_COMMAND_DESCRIPTOR)
+				.subcommand_required(true)
+				.arg_required_else_help(true)
+				.allow_external_subcommands(true)
+				.subcommand(
+					Command::new(CXL_FM_MLD_PORT_TUNNEL_COMMAND)
+						.about(CXL_FM_MLD_PORT_TUNNEL_COMMAND_DESCRIPTOR)
+				)
+				.subcommand(
+					Command::new(CXL_FM_MLD_PORT_SEND_CONFIG_COMMAND)
+						.about(CXL_FM_MLD_PORT_SEND_CONFIG_COMMAND_DESCRIPTOR)
+				)
+				.subcommand(
+					Command::new(CXL_FM_MLD_PORT_SEND_MEM_REQUEST_COMMAND)
+						.about(CXL_FM_MLD_PORT_SEND_MEM_REQUEST_COMMAND_DESCRIPTOR)
+				)
+		)
+		.subcommand(
+			Command::new(CXL_FM_DCD_COMMAND)
+				.about(CXL_FM_DCD_COMMAND_DESCRIPTOR)
+				.subcommand_required(true)
+				.arg_required_else_help(true)
+				.allow_external_subcommands(true)
+				.subcommand(
+					Command::new(CXL_FM_DCD_GET_INFO_COMMAND)
+						.about(CXL_FM_DCD_GET_INFO_COMMAND_DESCRIPTOR)
+				)
+				.subcommand(
+					Command::new(CXL_FM_DCD_GET_CONFIG_COMMAND)
+						.about(CXL_FM_DCD_GET_CONFIG_COMMAND_DESCRIPTOR)
+				)
+				.subcommand(
+					Command::new(CXL_FM_DCD_SET_CONFIG_COMMAND)
+						.about(CXL_FM_DCD_SET_CONFIG_COMMAND_DESCRIPTOR)
+				)
+				.subcommand(
+					Command::new(CXL_FM_DCD_GET_EXTENT_COMMAND)
+						.about(CXL_FM_DCD_GET_EXTENT_COMMAND_DESCRIPTOR)
+				)
+				.subcommand(
+					Command::new(CXL_FM_DCD_ADD_CAPACITY_COMMAND)
+						.about(CXL_FM_DCD_ADD_CAPACITY_COMMAND_DESCRIPTOR)
+				)
+				.subcommand(
+					Command::new(CXL_FM_DCD_RELEASE_CAPACITY_COMMAND)
+						.about(CXL_FM_DCD_RELEASE_CAPACITY_COMMAND_DESCRIPTOR)
+				)
+		)
+}
+
+/*
+ * Application logic
+ */
+fn main() {
+	let matches = cli().get_matches();
+
+	let ip = matches.get_one::<String>(CXL_FM_TOOL_IP_ADDRESS_OPTION).unwrap();
+	let port = matches.get_one::<String>(CXL_FM_TOOL_PORT_OPTION).unwrap();
+	let ip_port = format!("{ip}:{port}");
+
+	let options = CxlFmOptions {
+		ip_port: String::from(ip_port),
+		is_debug: matches.get_flag(CXL_FM_TOOL_DEBUG_OPTION) == true,
+	};
+
+	if options.is_debug {
+		println!("{} {}", CXL_FM_TOOL_NAME, CXL_FM_TOOL_VERSION);
+	}
+
+	match matches.subcommand() {
+		Some((CXL_FM_DISCOVER_COMMAND, discover)) => {
+			match discover.subcommand() {
+				Some((CXL_FM_DISCOVER_FM_COMMAND, fm)) => {
+					cxl_fm_discover_command::discover_fms(&fm,
+									      &options);
+				},
+				Some((CXL_FM_DISCOVER_DEVICES_COMMAND, devices)) => {
+					cxl_fm_discover_command::discover_cxl_devices(&devices,
+										      &options);
+				},
+				Some((CXL_FM_DISCOVER_SWITCHES_COMMAND, switch)) => {
+					cxl_fm_discover_command::discover_cxl_switches(&switch,
+											&options);
+				},
+				Some((CXL_FM_DISCOVER_LOGICAL_DEVICES_COMMAND, logical_devices)) => {
+					cxl_fm_discover_command::discover_logical_devices(&logical_devices,
+											  &options);
+				},
+				_ => unreachable!(),
+			}
+		},
+		Some((CXL_FM_COMMAND, fm)) => {
+			match fm.subcommand() {
+				Some((CXL_FM_GET_INFO_COMMAND, get_info)) => {
+					cxl_fm_command::get_info(&get_info,
+								 &options);
+				},
+				Some((CXL_FM_START_COMMAND, start)) => {
+					cxl_fm_command::start(&start,
+							      &options);
+				},
+				Some((CXL_FM_RESTART_COMMAND, restart)) => {
+					cxl_fm_command::restart(&restart,
+								&options);
+				},
+				Some((CXL_FM_STOP_COMMAND, stop)) => {
+					cxl_fm_command::stop(&stop,
+							     &options);
+				},
+				Some((CXL_FM_GET_CONFIG_COMMAND, get_config)) => {
+					cxl_fm_command::get_config(&get_config,
+								   &options);
+				},
+				Some((CXL_FM_SET_CONFIG_COMMAND, set_config)) => {
+					cxl_fm_command::set_config(&set_config,
+								   &options);
+				},
+				Some((CXL_FM_GET_EVENTS_COMMAND, get_events)) => {
+					cxl_fm_command::get_events(&get_events,
+								   &options);
+				},
+				_ => unreachable!(),
+			}
+		},
+		Some((CXL_FM_SWITCH_COMMAND, switch)) => {
+			match switch.subcommand() {
+				Some((CXL_FM_SWITCH_GET_INFO_COMMAND, get_info)) => {
+					cxl_switch_command::get_info(&get_info,
+								     &options);
+				},
+				Some((CXL_FM_SWITCH_GET_CONFIG_COMMAND, get_config)) => {
+					cxl_switch_command::get_config(&get_config,
+								       &options);
+				},
+				Some((CXL_FM_SWITCH_SET_CONFIG_COMMAND, set_config)) => {
+					cxl_switch_command::set_config(&set_config,
+									&options);
+				},
+				_ => unreachable!(),
+			}
+		},
+		Some((CXL_FM_MH_DEVICE_COMMAND, mh_device)) => {
+			match mh_device.subcommand() {
+				Some((CXL_FM_MH_DEVICE_GET_INFO_COMMAND, get_info)) => {
+					cxl_mh_device_command::get_info(&get_info,
+									&options);
+				},
+				_ => unreachable!(),
+			}
+		},
+		Some((CXL_FM_LOGICAL_DEVICE_COMMAND, logical_device)) => {
+			match logical_device.subcommand() {
+				Some((CXL_FM_LOGICAL_DEVICE_BIND_COMMAND, bind)) => {
+					cxl_logical_device_command::bind(&bind,
+									 &options);
+				},
+				Some((CXL_FM_LOGICAL_DEVICE_UNBIND_COMMAND, unbind)) => {
+					cxl_logical_device_command::unbind(&unbind,
+									   &options);
+				},
+				Some((CXL_FM_LOGICAL_DEVICE_CONNECT_COMMAND, connect)) => {
+					cxl_logical_device_command::connect(&connect,
+									    &options);
+				},
+				Some((CXL_FM_LOGICAL_DEVICE_DISCONNECT_COMMAND, disconnect)) => {
+					cxl_logical_device_command::disconnect(&disconnect,
+										&options);
+				},
+				Some((CXL_FM_LOGICAL_DEVICE_GET_ALLOCATION_COMMAND, get_allocation)) => {
+					cxl_logical_device_command::get_allocation(&get_allocation,
+										   &options);
+				},
+				Some((CXL_FM_LOGICAL_DEVICE_SET_ALLOCATION_COMMAND, set_allocation)) => {
+					cxl_logical_device_command::set_allocation(&set_allocation,
+										   &options);
+				},
+				Some((CXL_FM_LOGICAL_DEVICE_GET_QOS_CONTROL_COMMAND, get_qos_control)) => {
+					cxl_logical_device_command::get_qos_control(&get_qos_control,
+										    &options);
+				},
+				Some((CXL_FM_LOGICAL_DEVICE_SET_QOS_CONTROL_COMMAND, set_qos_control)) => {
+					cxl_logical_device_command::set_qos_control(&set_qos_control,
+										    &options);
+				},
+				Some((CXL_FM_LOGICAL_DEVICE_GET_QOS_STATUS_COMMAND, get_qos_status)) => {
+					cxl_logical_device_command::get_qos_status(&get_qos_status,
+										   &options);
+				},
+				Some((CXL_FM_LOGICAL_DEVICE_GET_QOS_BANDWIDTH_COMMAND, get_qos_bandwidth)) => {
+					cxl_logical_device_command::get_qos_bandwidth(&get_qos_bandwidth,
+										      &options);
+				},
+				Some((CXL_FM_LOGICAL_DEVICE_SET_QOS_BANDWIDTH_COMMAND, set_qos_bandwidth)) => {
+					cxl_logical_device_command::set_qos_bandwidth(&set_qos_bandwidth,
+										      &options);
+				},
+				Some((CXL_FM_LOGICAL_DEVICE_GET_QOS_BANDWIDTH_LIMIT_COMMAND, get_qos_bandwidth_limit)) => {
+					cxl_logical_device_command::get_qos_bandwidth_limit(&get_qos_bandwidth_limit,
+											    &options);
+				},
+				Some((CXL_FM_LOGICAL_DEVICE_SET_QOS_BANDWIDTH_LIMIT_COMMAND, set_qos_bandwidth_limit)) => {
+					cxl_logical_device_command::set_qos_bandwidth_limit(&set_qos_bandwidth_limit,
+											    &options);
+				},
+				Some((CXL_FM_LOGICAL_DEVICE_ERASE_COMMAND, erase)) => {
+					cxl_logical_device_command::erase(&erase,
+									  &options);
+				},
+				_ => unreachable!(),
+			}
+		},
+		Some((CXL_FM_PPB_COMMAND, ppb)) => {
+			match ppb.subcommand() {
+				Some((CXL_FM_PPB_CONFIG_COMMAND, config)) => {
+					cxl_ppb_command::config(&config,
+								&options);
+				},
+				Some((CXL_FM_PPB_BIND_COMMAND, bind)) => {
+					cxl_ppb_command::bind(&bind,
+							      &options);
+				},
+				Some((CXL_FM_PPB_UNBIND_COMMAND, unbind)) => {
+					cxl_ppb_command::unbind(&unbind,
+								&options);
+				},
+				_ => unreachable!(),
+			}
+		},
+		Some((CXL_FM_PHYSICAL_PORT_COMMAND, physical_port)) => {
+			match physical_port.subcommand() {
+				Some((CXL_FM_PHYSICAL_PORT_GET_INFO_COMMAND, get_info)) => {
+					cxl_physical_port_command::get_info(&get_info,
+									    &options);
+				},
+				Some((CXL_FM_PHYSICAL_PORT_CONTROL_COMMAND, control)) => {
+					cxl_physical_port_command::control(&control,
+									   &options);
+				},
+				Some((CXL_FM_PHYSICAL_PORT_BIND_COMMAND, bind)) => {
+					cxl_physical_port_command::bind(&bind,
+									&options);
+				},
+				Some((CXL_FM_PHYSICAL_PORT_UNBIND_COMMAND, unbind)) => {
+					cxl_physical_port_command::unbind(&unbind,
+									  &options);
+				},
+				_ => unreachable!(),
+			}
+		},
+		Some((CXL_FM_MLD_PORT_COMMAND, mld_port)) => {
+			match mld_port.subcommand() {
+				Some((CXL_FM_MLD_PORT_TUNNEL_COMMAND, tunnel)) => {
+					cxl_mld_port_command::tunnel(&tunnel,
+								     &options);
+				},
+				Some((CXL_FM_MLD_PORT_SEND_CONFIG_COMMAND, send_config)) => {
+					cxl_mld_port_command::send_config(&send_config,
+									  &options);
+				},
+				Some((CXL_FM_MLD_PORT_SEND_MEM_REQUEST_COMMAND, send_memory_request)) => {
+					cxl_mld_port_command::send_memory_request(&send_memory_request,
+										  &options);
+				},
+				_ => unreachable!(),
+			}
+		},
+		Some((CXL_FM_DCD_COMMAND, dcd)) => {
+			match dcd.subcommand() {
+				Some((CXL_FM_DCD_GET_INFO_COMMAND, get_info)) => {
+					cxl_dcd_command::get_info(&get_info,
+								  &options);
+				},
+				Some((CXL_FM_DCD_GET_CONFIG_COMMAND, get_capacity_config)) => {
+					cxl_dcd_command::get_capacity_config(&get_capacity_config,
+									     &options);
+				},
+				Some((CXL_FM_DCD_SET_CONFIG_COMMAND, set_capacity_config)) => {
+					cxl_dcd_command::set_capacity_config(&set_capacity_config,
+									     &options);
+				},
+				Some((CXL_FM_DCD_GET_EXTENT_COMMAND, get_extent_list)) => {
+					cxl_dcd_command::get_extent_list(&get_extent_list,
+									 &options);
+				},
+				Some((CXL_FM_DCD_ADD_CAPACITY_COMMAND, add_capacity)) => {
+					cxl_dcd_command::add_capacity(&add_capacity,
+								      &options);
+				},
+				Some((CXL_FM_DCD_RELEASE_CAPACITY_COMMAND, release_capacity)) => {
+					cxl_dcd_command::release_capacity(&release_capacity,
+									  &options);
+				},
+				_ => unreachable!(),
+			}
+		},
+		_ => unreachable!(),
+	}
+}
diff --git a/fm_cli/src/mld_port.rs b/fm_cli/src/mld_port.rs
new file mode 100644
index 0000000..f8ecbb3
--- /dev/null
+++ b/fm_cli/src/mld_port.rs
@@ -0,0 +1,126 @@ 
+/*
+ * CXL FM Infrastructure -- CXl Fabric Manager (FM) Infrastructure.
+ *
+ * CXL FM configuration tool implementation.
+ *
+ * Copyright (c) 2023 Viacheslav Dubeyko <slava@dubeyko.com>,
+ * All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+pub mod cxl_mld_port_command {
+	use clap::{ArgMatches};
+	use std::net::{TcpStream};
+	use fm_library::cxl_fm_lib::CxlFmOptions;
+	use fm_library::cxl_fm_lib::send_command;
+	use fm_library::cxl_fm_lib::CXL_FM_MLD_PORT_TUNNEL_COMMAND;
+	use fm_library::cxl_fm_lib::CXL_FM_MLD_PORT_SEND_CONFIG_COMMAND;
+	use fm_library::cxl_fm_lib::CXL_FM_MLD_PORT_SEND_MEM_REQ_COMMAND;
+
+	/*
+	 * Tunnel Management Command
+	 */
+	pub fn tunnel(options: &ArgMatches, env: &CxlFmOptions) {
+		if env.is_debug {
+			println!("{}", crate::CXL_FM_MLD_PORT_TUNNEL_COMMAND_DESCRIPTOR);
+		}
+
+		if options.args_present() {
+			/*
+			 * Ignore currently.
+			 * Add code later.
+			 */
+		}
+
+		match TcpStream::connect(&env.ip_port) {
+			Ok(mut stream) => {
+				if env.is_debug {
+					println!("Successfully connected to server: {}",
+						 env.ip_port);
+				}
+
+				send_command(&mut stream,
+					     CXL_FM_MLD_PORT_TUNNEL_COMMAND,
+					     &env);
+			},
+			Err(e) => {
+				println!("Failed to connect: {}", e);
+			}
+		}
+	}
+
+	/*
+	 * Send CXL.io configuration request
+	 */
+	pub fn send_config(options: &ArgMatches, env: &CxlFmOptions) {
+		if env.is_debug {
+			println!("{}", crate::CXL_FM_MLD_PORT_SEND_CONFIG_COMMAND_DESCRIPTOR);
+		}
+
+		if options.args_present() {
+			/*
+			 * Ignore currently.
+			 * Add code later.
+			 */
+		}
+
+		match TcpStream::connect(&env.ip_port) {
+			Ok(mut stream) => {
+				if env.is_debug {
+					println!("Successfully connected to server: {}",
+						 env.ip_port);
+				}
+
+				send_command(&mut stream,
+					     CXL_FM_MLD_PORT_SEND_CONFIG_COMMAND,
+					     &env);
+			},
+			Err(e) => {
+				println!("Failed to connect: {}", e);
+			}
+		}
+	}
+
+	/*
+	 * Send CXL.io memory request
+	 */
+	pub fn send_memory_request(options: &ArgMatches, env: &CxlFmOptions) {
+		if env.is_debug {
+			println!("{}", crate::CXL_FM_MLD_PORT_SEND_MEM_REQUEST_COMMAND_DESCRIPTOR);
+		}
+
+		if options.args_present() {
+			/*
+			 * Ignore currently.
+			 * Add code later.
+			 */
+		}
+
+		match TcpStream::connect(&env.ip_port) {
+			Ok(mut stream) => {
+				if env.is_debug {
+					println!("Successfully connected to server: {}",
+						 env.ip_port);
+				}
+
+				send_command(&mut stream,
+					     CXL_FM_MLD_PORT_SEND_MEM_REQ_COMMAND,
+					     &env);
+			},
+			Err(e) => {
+				println!("Failed to connect: {}", e);
+			}
+		}
+	}
+}
diff --git a/fm_cli/src/multi_headed_device.rs b/fm_cli/src/multi_headed_device.rs
new file mode 100644
index 0000000..00563fe
--- /dev/null
+++ b/fm_cli/src/multi_headed_device.rs
@@ -0,0 +1,60 @@ 
+/*
+ * CXL FM Infrastructure -- CXl Fabric Manager (FM) Infrastructure.
+ *
+ * CXL FM configuration tool implementation.
+ *
+ * Copyright (c) 2023 Viacheslav Dubeyko <slava@dubeyko.com>,
+ * All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+pub mod cxl_mh_device_command {
+	use clap::{ArgMatches};
+	use std::net::{TcpStream};
+	use fm_library::cxl_fm_lib::CxlFmOptions;
+	use fm_library::cxl_fm_lib::send_command;
+	use fm_library::cxl_fm_lib::CXL_FM_GET_MHD_INFO_COMMAND;
+
+	/*
+	 * Get Multi Headed Device (MHD) status/info
+	 */
+	pub fn get_info(options: &ArgMatches, env: &CxlFmOptions) {
+		if env.is_debug {
+			println!("{}", crate::CXL_FM_MH_DEVICE_GET_INFO_COMMAND_DESCRIPTOR);
+		}
+
+		if options.args_present() {
+			/*
+			 * Ignore currently.
+			 * Add code later.
+			 */
+		}
+
+		match TcpStream::connect(&env.ip_port) {
+			Ok(mut stream) => {
+				if env.is_debug {
+					println!("Successfully connected to server: {}",
+						 env.ip_port);
+				}
+
+				send_command(&mut stream,
+					     CXL_FM_GET_MHD_INFO_COMMAND,
+					     &env);
+			},
+			Err(e) => {
+				println!("Failed to connect: {}", e);
+			}
+		}
+	}
+}
diff --git a/fm_cli/src/pci2pci_bridge.rs b/fm_cli/src/pci2pci_bridge.rs
new file mode 100644
index 0000000..e7b82a5
--- /dev/null
+++ b/fm_cli/src/pci2pci_bridge.rs
@@ -0,0 +1,126 @@ 
+/*
+ * CXL FM Infrastructure -- CXl Fabric Manager (FM) Infrastructure.
+ *
+ * CXL FM configuration tool implementation.
+ *
+ * Copyright (c) 2023 Viacheslav Dubeyko <slava@dubeyko.com>,
+ * All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+pub mod cxl_ppb_command {
+	use clap::{ArgMatches};
+	use std::net::{TcpStream};
+	use fm_library::cxl_fm_lib::CxlFmOptions;
+	use fm_library::cxl_fm_lib::send_command;
+	use fm_library::cxl_fm_lib::CXL_FM_GET_PPB_CONFIG_COMMAND;
+	use fm_library::cxl_fm_lib::CXL_FM_PPB_BIND_COMMAND;
+	use fm_library::cxl_fm_lib::CXL_FM_PPB_UNBIND_COMMAND;
+
+	/*
+	 * Send PCI-to-PCI Bridge (PPB) configuration request
+	 */
+	pub fn config(options: &ArgMatches, env: &CxlFmOptions) {
+		if env.is_debug {
+			println!("{}", crate::CXL_FM_PPB_CONFIG_COMMAND_DESCRIPTOR);
+		}
+
+		if options.args_present() {
+			/*
+			 * Ignore currently.
+			 * Add code later.
+			 */
+		}
+
+		match TcpStream::connect(&env.ip_port) {
+			Ok(mut stream) => {
+				if env.is_debug {
+					println!("Successfully connected to server: {}",
+						 env.ip_port);
+				}
+
+				send_command(&mut stream,
+					     CXL_FM_GET_PPB_CONFIG_COMMAND,
+					     &env);
+			},
+			Err(e) => {
+				println!("Failed to connect: {}", e);
+			}
+		}
+	}
+
+	/*
+	 * Bind Virtual PCI-to-PCI Bridge (vPPB) inside a CXL switch
+	 */
+	pub fn bind(options: &ArgMatches, env: &CxlFmOptions) {
+		if env.is_debug {
+			println!("{}", crate::CXL_FM_PPB_BIND_COMMAND_DESCRIPTOR);
+		}
+
+		if options.args_present() {
+			/*
+			 * Ignore currently.
+			 * Add code later.
+			 */
+		}
+
+		match TcpStream::connect(&env.ip_port) {
+			Ok(mut stream) => {
+				if env.is_debug {
+					println!("Successfully connected to server: {}",
+						 env.ip_port);
+				}
+
+				send_command(&mut stream,
+					     CXL_FM_PPB_BIND_COMMAND,
+					     &env);
+			},
+			Err(e) => {
+				println!("Failed to connect: {}", e);
+			}
+		}
+	}
+
+	/*
+	 * Unbind Virtual PCI-to-PCI Bridge (vPPB) inside a CXL switch
+	 */
+	pub fn unbind(options: &ArgMatches, env: &CxlFmOptions) {
+		if env.is_debug {
+			println!("{}", crate::CXL_FM_PPB_UNBIND_COMMAND_DESCRIPTOR);
+		}
+
+		if options.args_present() {
+			/*
+			 * Ignore currently.
+			 * Add code later.
+			 */
+		}
+
+		match TcpStream::connect(&env.ip_port) {
+			Ok(mut stream) => {
+				if env.is_debug {
+					println!("Successfully connected to server: {}",
+						 env.ip_port);
+				}
+
+				send_command(&mut stream,
+					     CXL_FM_PPB_UNBIND_COMMAND,
+					     &env);
+			},
+			Err(e) => {
+				println!("Failed to connect: {}", e);
+			}
+		}
+	}
+}
diff --git a/fm_cli/src/physical_port.rs b/fm_cli/src/physical_port.rs
new file mode 100644
index 0000000..6e887ed
--- /dev/null
+++ b/fm_cli/src/physical_port.rs
@@ -0,0 +1,159 @@ 
+/*
+ * CXL FM Infrastructure -- CXl Fabric Manager (FM) Infrastructure.
+ *
+ * CXL FM configuration tool implementation.
+ *
+ * Copyright (c) 2023 Viacheslav Dubeyko <slava@dubeyko.com>,
+ * All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+pub mod cxl_physical_port_command {
+	use clap::{ArgMatches};
+	use std::net::{TcpStream};
+	use fm_library::cxl_fm_lib::CxlFmOptions;
+	use fm_library::cxl_fm_lib::send_command;
+	use fm_library::cxl_fm_lib::CXL_FM_GET_PHYSICAL_PORT_INFO_COMMAND;
+	use fm_library::cxl_fm_lib::CXL_FM_PHYSICAL_PORT_CONTROL_COMMAND;
+	use fm_library::cxl_fm_lib::CXL_FM_BIND_PHYSICAL_PORT_COMMAND;
+	use fm_library::cxl_fm_lib::CXL_FM_UNBIND_PHYSICAL_PORT_COMMAND;
+
+	/*
+	 * Get state of physical port
+	 */
+	pub fn get_info(options: &ArgMatches, env: &CxlFmOptions) {
+		if env.is_debug {
+			println!("{}", crate::CXL_FM_PHYSICAL_PORT_GET_INFO_COMMAND_DESCRIPTOR);
+		}
+
+		if options.args_present() {
+			/*
+			 * Ignore currently.
+			 * Add code later.
+			 */
+		}
+
+		match TcpStream::connect(&env.ip_port) {
+			Ok(mut stream) => {
+				if env.is_debug {
+					println!("Successfully connected to server: {}",
+						 env.ip_port);
+				}
+
+				send_command(&mut stream,
+					     CXL_FM_GET_PHYSICAL_PORT_INFO_COMMAND,
+					     &env);
+			},
+			Err(e) => {
+				println!("Failed to connect: {}", e);
+			}
+		}
+	}
+
+	/*
+	 * Control physical port
+	 */
+	pub fn control(options: &ArgMatches, env: &CxlFmOptions) {
+		if env.is_debug {
+			println!("{}", crate::CXL_FM_PHYSICAL_PORT_CONTROL_COMMAND_DESCRIPTOR);
+		}
+
+		if options.args_present() {
+			/*
+			 * Ignore currently.
+			 * Add code later.
+			 */
+		}
+
+		match TcpStream::connect(&env.ip_port) {
+			Ok(mut stream) => {
+				if env.is_debug {
+					println!("Successfully connected to server: {}",
+						 env.ip_port);
+				}
+
+				send_command(&mut stream,
+					     CXL_FM_PHYSICAL_PORT_CONTROL_COMMAND,
+					     &env);
+			},
+			Err(e) => {
+				println!("Failed to connect: {}", e);
+			}
+		}
+	}
+
+	/*
+	 * Bind physical port to Virtual PCI-to-PCI Bridge (vPPB)
+	 */
+	pub fn bind(options: &ArgMatches, env: &CxlFmOptions) {
+		if env.is_debug {
+			println!("{}", crate::CXL_FM_PHYSICAL_PORT_BIND_COMMAND_DESCRIPTOR);
+		}
+
+		if options.args_present() {
+			/*
+			 * Ignore currently.
+			 * Add code later.
+			 */
+		}
+
+		match TcpStream::connect(&env.ip_port) {
+			Ok(mut stream) => {
+				if env.is_debug {
+					println!("Successfully connected to server: {}",
+						 env.ip_port);
+				}
+
+				send_command(&mut stream,
+					     CXL_FM_BIND_PHYSICAL_PORT_COMMAND,
+					     &env);
+			},
+			Err(e) => {
+				println!("Failed to connect: {}", e);
+			}
+		}
+	}
+
+	/*
+	 * Unbind physical port from Virtual PCI-to-PCI Bridge (vPPB)
+	 */
+	pub fn unbind(options: &ArgMatches, env: &CxlFmOptions) {
+		if env.is_debug {
+			println!("{}", crate::CXL_FM_PHYSICAL_PORT_UNBIND_COMMAND_DESCRIPTOR);
+		}
+
+		if options.args_present() {
+			/*
+			 * Ignore currently.
+			 * Add code later.
+			 */
+		}
+
+		match TcpStream::connect(&env.ip_port) {
+			Ok(mut stream) => {
+				if env.is_debug {
+					println!("Successfully connected to server: {}",
+						 env.ip_port);
+				}
+
+				send_command(&mut stream,
+					     CXL_FM_UNBIND_PHYSICAL_PORT_COMMAND,
+					     &env);
+			},
+			Err(e) => {
+				println!("Failed to connect: {}", e);
+			}
+		}
+	}
+}
diff --git a/fm_cli/src/switch.rs b/fm_cli/src/switch.rs
new file mode 100644
index 0000000..404bb07
--- /dev/null
+++ b/fm_cli/src/switch.rs
@@ -0,0 +1,126 @@ 
+/*
+ * CXL FM Infrastructure -- CXl Fabric Manager (FM) Infrastructure.
+ *
+ * CXL FM configuration tool implementation.
+ *
+ * Copyright (c) 2023 Viacheslav Dubeyko <slava@dubeyko.com>,
+ * All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+pub mod cxl_switch_command {
+	use clap::{ArgMatches};
+	use std::net::{TcpStream};
+	use fm_library::cxl_fm_lib::CxlFmOptions;
+	use fm_library::cxl_fm_lib::send_command;
+	use fm_library::cxl_fm_lib::CXL_FM_GET_SWITCH_INFO_COMMAND;
+	use fm_library::cxl_fm_lib::CXL_FM_GET_SWITCH_CONFIG_COMMAND;
+	use fm_library::cxl_fm_lib::CXL_FM_SET_SWITCH_CONFIG_COMMAND;
+
+	/*
+	 * Get CXL switch status/info
+	 */
+	pub fn get_info(options: &ArgMatches, env: &CxlFmOptions) {
+		if env.is_debug {
+			println!("{}", crate::CXL_FM_SWITCH_GET_INFO_COMMAND_DESCRIPTOR);
+		}
+
+		if options.args_present() {
+			/*
+			 * Ignore currently.
+			 * Add code later.
+			 */
+		}
+
+		match TcpStream::connect(&env.ip_port) {
+			Ok(mut stream) => {
+				if env.is_debug {
+					println!("Successfully connected to server: {}",
+						 env.ip_port);
+				}
+
+				send_command(&mut stream,
+					     CXL_FM_GET_SWITCH_INFO_COMMAND,
+					     &env);
+			},
+			Err(e) => {
+				println!("Failed to connect: {}", e);
+			}
+		}
+	}
+
+	/*
+	 * Get CXL switch configuration
+	 */
+	pub fn get_config(options: &ArgMatches, env: &CxlFmOptions) {
+		if env.is_debug {
+			println!("{}", crate::CXL_FM_SWITCH_GET_CONFIG_COMMAND_DESCRIPTOR);
+		}
+
+		if options.args_present() {
+			/*
+			 * Ignore currently.
+			 * Add code later.
+			 */
+		}
+
+		match TcpStream::connect(&env.ip_port) {
+			Ok(mut stream) => {
+				if env.is_debug {
+					println!("Successfully connected to server: {}",
+						 env.ip_port);
+				}
+
+				send_command(&mut stream,
+					     CXL_FM_GET_SWITCH_CONFIG_COMMAND,
+					     &env);
+			},
+			Err(e) => {
+				println!("Failed to connect: {}", e);
+			}
+		}
+	}
+
+	/*
+	 * Set CXL switch configuration
+	 */
+	pub fn set_config(options: &ArgMatches, env: &CxlFmOptions) {
+		if env.is_debug {
+			println!("{}", crate::CXL_FM_SWITCH_SET_CONFIG_COMMAND_DESCRIPTOR);
+		}
+
+		if options.args_present() {
+			/*
+			 * Ignore currently.
+			 * Add code later.
+			 */
+		}
+
+		match TcpStream::connect(&env.ip_port) {
+			Ok(mut stream) => {
+				if env.is_debug {
+					println!("Successfully connected to server: {}",
+						 env.ip_port);
+				}
+
+				send_command(&mut stream,
+					     CXL_FM_SET_SWITCH_CONFIG_COMMAND,
+					     &env);
+			},
+			Err(e) => {
+				println!("Failed to connect: {}", e);
+			}
+		}
+	}
+}