[dpdk-dev,v4,1/5] lib: add Port Representor library

Message ID 20180108143720.7994-2-remy.horton@intel.com (mailing list archive)
State Superseded, archived
Delegated to: Thomas Monjalon
Headers

Checks

Context Check Description
ci/checkpatch warning coding style issues
ci/Intel-compilation fail Compilation issues

Commit Message

Remy Horton Jan. 8, 2018, 2:37 p.m. UTC
  Port Representors provide a logical presentation in DPDK of VF (virtual
function) ports for the purposes of control and monitoring. Each port
representor device represents a single VF and is associated with it's
parent physical function (PF) PMD which provides the back-end hooks for
the representor device ops and defines the control domain to which that
port belongs. This allows to use existing DPDK APIs to monitor and control
the port without the need to create and maintain VF specific APIs.

The library provides the broker infrastructure to be instantiated by
base driver and corresponding methods to manage the broker
infrastructure. The broker keeps records of list of representor PMDs.
The library also provides methods to manage the representor PMDs by the
broker.

Signed-off-by: Declan Doherty <declan.doherty@intel.com>
Signed-off-by: Mohammad Abdul Awal <mohammad.abdul.awal@intel.com>
Signed-off-by: Remy Horton <remy.horton@intel.com>
---
 MAINTAINERS                                        |   8 +-
 config/common_base                                 |   5 +
 doc/api/doxy-api-index.md                          |   3 +-
 doc/api/doxy-api.conf                              |   1 +
 doc/guides/prog_guide/index.rst                    |   1 +
 doc/guides/prog_guide/representor_lib.rst          |  62 ++++
 doc/guides/rel_notes/release_18_02.rst             |   9 +
 lib/Makefile                                       |   3 +
 lib/librte_representor/Makefile                    |  26 ++
 lib/librte_representor/rte_port_representor.c      | 326 +++++++++++++++++++++
 lib/librte_representor/rte_port_representor.h      |  60 ++++
 .../rte_port_representor_driver.h                  | 138 +++++++++
 .../rte_port_representor_version.map               |   8 +
 mk/rte.app.mk                                      |   1 +
 14 files changed, 649 insertions(+), 2 deletions(-)
 create mode 100644 doc/guides/prog_guide/representor_lib.rst
 create mode 100644 lib/librte_representor/Makefile
 create mode 100644 lib/librte_representor/rte_port_representor.c
 create mode 100644 lib/librte_representor/rte_port_representor.h
 create mode 100644 lib/librte_representor/rte_port_representor_driver.h
 create mode 100644 lib/librte_representor/rte_port_representor_version.map
  

Comments

Ferruh Yigit Jan. 9, 2018, 10:06 p.m. UTC | #1
On 1/8/2018 2:37 PM, Remy Horton wrote:
> Port Representors provide a logical presentation in DPDK of VF (virtual
> function) ports for the purposes of control and monitoring. Each port
> representor device represents a single VF and is associated with it's
> parent physical function (PF) PMD which provides the back-end hooks for
> the representor device ops and defines the control domain to which that
> port belongs. This allows to use existing DPDK APIs to monitor and control
> the port without the need to create and maintain VF specific APIs.
> 
> The library provides the broker infrastructure to be instantiated by
> base driver and corresponding methods to manage the broker
> infrastructure. The broker keeps records of list of representor PMDs.
> The library also provides methods to manage the representor PMDs by the
> broker.
> 
> Signed-off-by: Declan Doherty <declan.doherty@intel.com>
> Signed-off-by: Mohammad Abdul Awal <mohammad.abdul.awal@intel.com>
> Signed-off-by: Remy Horton <remy.horton@intel.com>

<...>

> @@ -788,7 +795,6 @@ F: doc/guides/sample_app_ug/test_pipeline.rst
>  F: examples/ip_pipeline/
>  F: doc/guides/sample_app_ug/ip_pipeline.rst
>  
> -

Can drop this. Two line break is intentional I think.

<...>

> @@ -820,3 +820,8 @@ CONFIG_RTE_APP_CRYPTO_PERF=y
>  # Compile the eventdev application
>  #
>  CONFIG_RTE_APP_EVENTDEV=y
> +
> +#
> +# Compile representor PMD
> +#
> +CONFIG_RTE_LIBRTE_REPRESENTOR=y

Last section of the config is for apps, can you please group this with libraries?

> diff --git a/doc/api/doxy-api-index.md b/doc/api/doxy-api-index.md
> index 3492702..5020a40 100644
> --- a/doc/api/doxy-api-index.md
> +++ b/doc/api/doxy-api-index.md
> @@ -50,7 +50,8 @@ The public API headers are grouped by topics:
>    [bitrate]            (@ref rte_bitrate.h),
>    [latency]            (@ref rte_latencystats.h),
>    [devargs]            (@ref rte_devargs.h),
> -  [PCI]                (@ref rte_pci.h)
> +  [PCI]                (@ref rte_pci.h),
> +  [Port Representor]   (@ref rte_port_representor.h)

Since this is related to the ethdev, I would put this after rte_mtr.

<....>

> @@ -41,6 +41,15 @@ New Features
>       Also, make sure to start the actual text at the margin.
>       =========================================================
>  
> +* **Added Port Representor functionality.**
> +
> +  Port Representors provide a logical presentation in DPDK of VF (virtual
> +  function) ports for the purposes of control and monitoring. Each port
> +  representor device represents a single VF and is associated with it's
> +  parent PF (physical function) PMD which provides the back-end hooks for
> +  the representor device ops and defines the control domain to which that
> +  port belongs.
> +

Can you please add new library to the "Shared Library Versions" section of the
release notes?

<...>

> @@ -0,0 +1,26 @@
> +# SPDX-License-Identifier: BSD-3-Clause
> +# Copyright(c) 2017 Intel Corporation. All rights reserved.

Can drop "All rights reserved." part, for all files.

<...>

> +	RTE_LOG(INFO, EAL, "Registered [%s_%s] broker.\n", broker->bus,
> +		broker->device);

Shouldn't use EAL type, this is a new library and it should dynamically register
its new type. Same for all log occurrence.

<...>

> +	TAILQ_FOREACH(broker, &broker_list, next) {
> +		if ((strcmp(broker->bus, bus) == 0) &&
> +				(strcmp(broker->device, device) == 0))
> +			break;
> +	}

Is there any type of synchronization required to protect the list?

<...>

> +#define RTE_REPRESENTOR_PORT_VALID_ETHDEV_OR_RET_ERR(ethdev, retval) do { \
> +	if (!strstr(ethdev->data->name, RTE_PORT_REPRESENTOR_DEVICE_NAME)) { \
> +		RTE_PMD_DEBUG_TRACE("port %d is not a representor port", \

RTE_PMD_DEBUG_TRACE prints in PMD type, please don't use it in this library.

<...>

> +	RTE_LOG(INFO, PMD, "Creating representor for VF %i from %s\n",
> +		vport_id, pf_addr_str);

Please don't use PMD type logs in library.

<...>

> +	/* Allocate private ethdev data for Port Representor info */
> +	rep_ethdev->data->dev_private = rte_malloc("rte_representor_port",
> +			sizeof(struct rte_representor_port), 0);
> +	if (rep_ethdev == NULL) {
> +		RTE_LOG(ERR, PMD, "Unable to allocate Port Representor"
> +			" private ethdev data\n");
> +		rte_eth_dev_release_port(rep_ethdev);

free rep_ethdev->data->mac_addrs ?

> +		return -ENOMEM;
> +	}
> +
> +	/* Allocate an rte_device & rte_driver for the ethdev. */
> +	rep_port->rep_pcidev = rte_zmalloc_socket("rte_device",
> +		sizeof(struct rte_device), 0, rte_socket_id());
> +	if (rep_port->rep_pcidev == NULL) {
> +		RTE_LOG(ERR, PMD, "Unable to allocate Port Representor"
> +			" devive\n");
> +		return -ENOMEM;
> +	}
> +	rep_port->rep_pcidrv = rte_zmalloc_socket("rte_driver",
> +		sizeof(struct rte_driver), 0, rte_socket_id());
> +	if (rep_port->rep_pcidrv == NULL) {
> +		RTE_LOG(ERR, PMD, "Unable to allocate Port Representor"
> +			" driver\n");
> +		return -ENOMEM;
> +	}
> +	rep_port->rep_pcidrv->name = RTE_PORT_REPRESENTOR_DEVICE_NAME;
> +	rep_port->rep_pcidev->driver = rep_port->rep_pcidrv;
> +	rep_ethdev->device = rep_port->rep_pcidev;
> +
> +	/* Register representor with broker */
> +	RTE_REPRESENTOR_PORT_VALID_ETHDEV_OR_RET_ERR(rep_ethdev, -EINVAL);
> +	rep_port->vport_id = vport_id;
> +	rep_port->ethdev = rep_ethdev;
> +	rep_port->broker = broker;
> +	rep_port->state = RTE_REPRESENTOR_PORT_VALID;
> +	rep_ethdev->data->dev_private = rep_port;

If so why allocated rep_ethdev->data->dev_private a few lines above? Am I
missing something?

> +
> +	RTE_FUNC_PTR_OR_ERR_RET(broker->ops->port_init, -ENOTSUP);

Do we need to free anything in case error?

> +	retval = broker->ops->port_init(broker, rep_ethdev);
> +	if (retval) {
> +		rte_eth_dev_release_port(rep_ethdev);

Need to free allocated mem.

<...>

> +	/* Free up representor */
> +	RTE_FUNC_PTR_OR_ERR_RET(rep_port->broker->ops->port_uninit, -ENOTSUP);
> +	rep_port->broker->ops->port_uninit(rep_port->broker, rep_port->ethdev);
> +	rep_port->state = RTE_REPRESENTOR_PORT_INVALID;
> +	rte_eth_dev_release_port(rep_port->ethdev);

I guess need to free data->mac_addrs too

<...>

> +/**
> + * Unregister a representor port, called during destruction of representor
> + * ethdev context. Freeing any allocated memory for the representor port.
> + *
> + * @param	pf_addr_str	Address of parent PF in Bus_DomBDF format
> + * @param	vport_id	Virtual port ID to deregister
> + *
> + * @return
> + * - 0 on success
> + * - errno on failure
> + */
> +int
> +rte_representor_port_unregister(char *pf_addr_str, uint32_t vport_id);

There was discussion about having new APIs as EXPERIMENTAL for a release, is it
agreed on. John, Luca do you remember?

<...>

> +struct rte_representor_broker {
> +	TAILQ_ENTRY(rte_representor_broker) next;
> +	/**< Next broker object in linked list */
> +
> +	const char *bus;	/**< bus name */
> +	const char *device;	/**< device name */
> +
> +	uint16_t nb_virtual_ports;
> +	/**< number of virtual ports supported by device */
> +
> +	struct rte_representor_port *vports;
> +	/**< Representor port contexts */
> +
> +	struct rte_representor_broker_port_ops *ops;
> +	/**< broker port operations functions */
> +	void *private_data;
> +	/**< broker private data */

Is this private_data used?

> +};
> +
> +/** Port Representor */
> +struct rte_representor_port {
> +	uint16_t vport_id;
> +	/**< Virtual Port Identifier */
> +	struct rte_eth_dev *ethdev;
> +	/**< ethdev handle of representor port */
> +	struct rte_representor_broker *broker;
> +	/**< Broker handle to allow reverse lookup */
> +	enum {
> +		RTE_REPRESENTOR_PORT_INVALID,
> +		/**< No ethdev instantiated for virtual port */
> +		RTE_REPRESENTOR_PORT_VALID
> +		/**< ethdev active for virtual port */
> +	} state;

What do you think moving enum decleration out of struct, for simplicity?

> +	/**< port state */
> +	void *priv_data;
> +	/**<  port private data */
> +	/**< Representor ethdev device */
> +	struct rte_device *rep_pcidev;
> +	/**< Representor ethdev driver */
> +	struct rte_driver *rep_pcidrv;

Is this only for pci bus? If not it can be good to rename.
  
Remy Horton Jan. 10, 2018, 11:40 a.m. UTC | #2
On 09/01/2018 22:06, Ferruh Yigit wrote:
> On 1/8/2018 2:37 PM, Remy Horton wrote:
[..]

>> +	TAILQ_FOREACH(broker, &broker_list, next) {
> Is there any type of synchronization required to protect the list?

Might be required if an app decides to call the functions from multiple 
lcores, but in that circumstance locking probably should be the 
responsibility of the app.


> There was discussion about having new APIs as EXPERIMENTAL for a release, is it
> agreed on. John, Luca do you remember?

I also remember some discussion along those lines, but not sure what the 
final outcome was.


>> +	void *private_data;
>> +	/**< broker private data */
>
> Is this private_data used?

The PMD-specific port representor support functions use it.
  

Patch

diff --git a/MAINTAINERS b/MAINTAINERS
index e0199b1..5828b94 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -775,6 +775,13 @@  F: doc/guides/prog_guide/pdump_lib.rst
 F: app/pdump/
 F: doc/guides/tools/pdump.rst
 
+Port Representors
+M: Declan Doherty <declan.doherty@intel.com>
+M: Mohammad Abdul Awal <mohammad.abdul.awal@intel.com>
+M: Remy Horton <remy.horton@intel.com>
+F: lib/librte_representor
+F: doc/guides/prog_guide/representor_lib.rst
+
 Packet Framework
 ----------------
 M: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
@@ -788,7 +795,6 @@  F: doc/guides/sample_app_ug/test_pipeline.rst
 F: examples/ip_pipeline/
 F: doc/guides/sample_app_ug/ip_pipeline.rst
 
-
 Algorithms
 ----------
 
diff --git a/config/common_base b/config/common_base
index e74febe..febb80a 100644
--- a/config/common_base
+++ b/config/common_base
@@ -820,3 +820,8 @@  CONFIG_RTE_APP_CRYPTO_PERF=y
 # Compile the eventdev application
 #
 CONFIG_RTE_APP_EVENTDEV=y
+
+#
+# Compile representor PMD
+#
+CONFIG_RTE_LIBRTE_REPRESENTOR=y
diff --git a/doc/api/doxy-api-index.md b/doc/api/doxy-api-index.md
index 3492702..5020a40 100644
--- a/doc/api/doxy-api-index.md
+++ b/doc/api/doxy-api-index.md
@@ -50,7 +50,8 @@  The public API headers are grouped by topics:
   [bitrate]            (@ref rte_bitrate.h),
   [latency]            (@ref rte_latencystats.h),
   [devargs]            (@ref rte_devargs.h),
-  [PCI]                (@ref rte_pci.h)
+  [PCI]                (@ref rte_pci.h),
+  [Port Representor]   (@ref rte_port_representor.h)
 
 - **device specific**:
   [softnic]            (@ref rte_eth_softnic.h),
diff --git a/doc/api/doxy-api.conf b/doc/api/doxy-api.conf
index b2cbe94..4d1b89f 100644
--- a/doc/api/doxy-api.conf
+++ b/doc/api/doxy-api.conf
@@ -70,6 +70,7 @@  INPUT                   = doc/api/doxy-api-index.md \
                           lib/librte_port \
                           lib/librte_power \
                           lib/librte_reorder \
+                          lib/librte_representor \
                           lib/librte_ring \
                           lib/librte_sched \
                           lib/librte_security \
diff --git a/doc/guides/prog_guide/index.rst b/doc/guides/prog_guide/index.rst
index c4beb34..380d5c9 100644
--- a/doc/guides/prog_guide/index.rst
+++ b/doc/guides/prog_guide/index.rst
@@ -71,6 +71,7 @@  Programmer's Guide
     power_man
     packet_classif_access_ctrl
     packet_framework
+    representor_lib
     vhost_lib
     metrics_lib
     port_hotplug_framework
diff --git a/doc/guides/prog_guide/representor_lib.rst b/doc/guides/prog_guide/representor_lib.rst
new file mode 100644
index 0000000..aaac6c9
--- /dev/null
+++ b/doc/guides/prog_guide/representor_lib.rst
@@ -0,0 +1,62 @@ 
+..  SPDX-License-Identifier: BSD-3-Clause
+    Copyright(c) 2017 Intel Corporation. All rights reserved.
+
+.. _Representor_Library:
+
+Port Representor Library
+========================
+
+Port representors provide a logical presentation in DPDK of VF (virtual
+function) ports for the purposes of control and monitoring. Each port
+representor device represents a single VF and is associated with it's
+parent physical function (PF) PMD which provides the back-end hooks for
+the representor device ops and defines the control domain to which that
+port belongs. This allows to use existing DPDK APIs to monitor and control
+the port without the need to create and maintain VF specific APIs.
+
+Initialising the library
+------------------------
+
+Before port representors can be used, the port broker infrastructure
+has to be enabled within the EAL. This is done by passing the
+``--enable-representor`` EAL command-line parameter:
+
+.. code-block:: c
+
+    ./testpmd --enable-representor -- -i
+
+
+Registering a Port Representor
+------------------------------
+Before use, port representors have to be individually *registered*
+with the broker associated with the physical function. This requires
+the physical function's address in *DomBDF* (domain bus device function)
+format and the zero-based index of the virtual function. For instance, to
+create port representors for the first two virtual functions associated
+with physical function with device address ``0000:81:00.0`` on the PCI
+bus, the following code could be used:
+
+.. code-block:: c
+
+    uint16_t port_id_0;
+    uint16_t port_id_1;
+
+    rte_representor_port_register("pci_0000:81:00.0", 0, &port_id_0);
+    rte_representor_port_register("pci_0000:81:00.0", 1, &port_id_1);
+
+Upon successful registration, these functions return zero, and the
+passed-in pointer to integer is set to the ethdev port ID for the
+created port representor.
+
+Unregistering a Port Representor
+--------------------------------
+
+Unregistering a port representor that is no longer required uses the
+same parameters used to register it, namely the physical function address
+and virtual function index. There is no need for port representors to be
+unregistered in any particular order:
+
+.. code-block:: c
+
+    rte_representor_port_unregister("pci_0000:81:00.0", 0);
+    rte_representor_port_unregister("pci_0000:81:00.0", 1);
diff --git a/doc/guides/rel_notes/release_18_02.rst b/doc/guides/rel_notes/release_18_02.rst
index 24b67bb..10fe433 100644
--- a/doc/guides/rel_notes/release_18_02.rst
+++ b/doc/guides/rel_notes/release_18_02.rst
@@ -41,6 +41,15 @@  New Features
      Also, make sure to start the actual text at the margin.
      =========================================================
 
+* **Added Port Representor functionality.**
+
+  Port Representors provide a logical presentation in DPDK of VF (virtual
+  function) ports for the purposes of control and monitoring. Each port
+  representor device represents a single VF and is associated with it's
+  parent PF (physical function) PMD which provides the back-end hooks for
+  the representor device ops and defines the control domain to which that
+  port belongs.
+
 
 API Changes
 -----------
diff --git a/lib/Makefile b/lib/Makefile
index 4202702..42932a9 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -73,6 +73,9 @@  DEPDIRS-librte_distributor := librte_eal librte_mbuf librte_ether
 DIRS-$(CONFIG_RTE_LIBRTE_PORT) += librte_port
 DEPDIRS-librte_port := librte_eal librte_mempool librte_mbuf librte_ether
 DEPDIRS-librte_port += librte_ip_frag librte_sched
+DIRS-$(CONFIG_RTE_LIBRTE_REPRESENTOR) += librte_representor
+DEPDIRS-librte_representor += librte_ether
+
 ifeq ($(CONFIG_RTE_LIBRTE_KNI),y)
 DEPDIRS-librte_port += librte_kni
 endif
diff --git a/lib/librte_representor/Makefile b/lib/librte_representor/Makefile
new file mode 100644
index 0000000..4060cc6
--- /dev/null
+++ b/lib/librte_representor/Makefile
@@ -0,0 +1,26 @@ 
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2017 Intel Corporation. All rights reserved.
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+#
+# library name
+#
+LIB = librte_representor.a
+
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+
+EXPORT_MAP := rte_port_representor_version.map
+
+LIBABIVER := 1
+
+SRCS-$(CONFIG_RTE_LIBRTE_REPRESENTOR) += rte_port_representor.c
+
+#
+# Export include files
+#
+SYMLINK-$(CONFIG_RTE_LIBRTE_REPRESENTOR)-include += rte_port_representor.h
+SYMLINK-$(CONFIG_RTE_LIBRTE_REPRESENTOR)-include += rte_port_representor_driver.h
+
+include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/lib/librte_representor/rte_port_representor.c b/lib/librte_representor/rte_port_representor.c
new file mode 100644
index 0000000..69a4bfc
--- /dev/null
+++ b/lib/librte_representor/rte_port_representor.c
@@ -0,0 +1,326 @@ 
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2017 Intel Corporation. All rights reserved.
+ */
+
+#include <rte_port_representor.h>
+#include <rte_port_representor_driver.h>
+
+#include <rte_kvargs.h>
+
+TAILQ_HEAD(rte_broker_list, rte_representor_broker);
+
+struct rte_broker_list broker_list =
+	TAILQ_HEAD_INITIALIZER(broker_list);
+
+struct port_rep_parameters {
+	uint64_t vport_mask;
+	struct {
+		char bus[RTE_DEV_NAME_MAX_LEN];
+		char device[RTE_DEV_NAME_MAX_LEN];
+	} parent;
+};
+
+/* Macros to check for valid id */
+#define RTE_VERIFY_OR_ERR_RET(val, retval) do { \
+	if (!(val)) { \
+		RTE_PMD_DEBUG_TRACE("verify failed, ret= %d", (retval)); \
+		return retval; \
+	} \
+} while (0)
+
+#define RTE_VERIFY_OR_RET(val) do { \
+	if (!(val)) { \
+		RTE_PMD_DEBUG_TRACE("verify failed"); \
+		return; \
+	} \
+} while (0)
+
+int
+rte_representor_broker_init(struct rte_representor_broker *broker)
+{
+	RTE_VERIFY_OR_ERR_RET(broker, -ENODEV);
+
+	RTE_VERIFY_OR_ERR_RET(broker->bus && strlen(broker->bus), -ENXIO);
+	RTE_VERIFY_OR_ERR_RET(broker->device && strlen(broker->device), -ENXIO);
+
+	RTE_VERIFY_OR_ERR_RET(broker->nb_virtual_ports > 0, -EINVAL);
+
+	broker->vports = rte_malloc("rte_representor_ports",
+		sizeof(*(broker->vports)) * broker->nb_virtual_ports, 0);
+	if (broker->vports == NULL)
+		return -ENOMEM;
+
+	RTE_VERIFY_OR_ERR_RET(broker->ops, -EINVAL);
+
+	TAILQ_INSERT_TAIL(&broker_list, broker, next);
+	RTE_LOG(INFO, EAL, "Registered [%s_%s] broker.\n", broker->bus,
+		broker->device);
+
+	return 0;
+}
+
+int
+rte_representor_broker_uninit(struct rte_representor_broker *broker)
+{
+	int i;
+	struct rte_eth_dev *ethdev;
+	char name[RTE_DEV_NAME_MAX_LEN];
+
+	for (i = 0; i < broker->nb_virtual_ports; i++) {
+		if (broker->vports[i].state == RTE_REPRESENTOR_PORT_VALID) {
+			ethdev = broker->vports[i].ethdev;
+			rte_eth_dev_detach(ethdev->data->port_id,
+				name);
+		}
+	}
+
+	rte_free(broker->vports);
+
+	TAILQ_REMOVE(&broker_list, broker, next);
+	RTE_LOG(DEBUG, EAL, "Unregistered [%s_%s] broker.\n", broker->bus,
+		broker->device);
+
+	return 0;
+}
+
+struct rte_representor_broker *
+rte_representor_broker_find(const char *bus, const char *device)
+{
+	struct rte_representor_broker *broker = NULL;
+
+	TAILQ_FOREACH(broker, &broker_list, next) {
+		if ((strcmp(broker->bus, bus) == 0) &&
+				(strcmp(broker->device, device) == 0))
+			break;
+	}
+
+	return broker;
+}
+
+#define RTE_REPRESENTOR_PORT_VALID_ETHDEV_OR_RET_ERR(ethdev, retval) do { \
+	if (!strstr(ethdev->data->name, RTE_PORT_REPRESENTOR_DEVICE_NAME)) { \
+		RTE_PMD_DEBUG_TRACE("port %d is not a representor port", \
+			ethdev->data.port_id); \
+		return retval; \
+	} \
+} while (0)
+
+#define RTE_REPRESENTOR_PORT_VALID_OR_RET_ERR(vport, retval) do { \
+	if (!(vport->state == RTE_REPRESENTOR_PORT_VALID)) { \
+		RTE_PMD_DEBUG_TRACE("Vport is not a representor port"); \
+		return retval; \
+	} \
+} while (0)
+
+static struct rte_representor_port *
+representor_port_find(struct rte_representor_broker *broker,
+		uint16_t vport_id)
+{
+	if (vport_id >= broker->nb_virtual_ports)
+		return NULL;
+
+	return &broker->vports[vport_id];
+}
+
+int
+rte_representor_port_register(char *pf_addr_str,
+		uint32_t vport_id, uint16_t *port_id)
+{
+	struct rte_eth_dev *rep_ethdev;
+	struct rte_representor_port *rep_port;
+	struct rte_representor_broker *broker;
+	char str_device_name[RTE_ETH_NAME_MAX_LEN];
+	int len_name;
+	int retval;
+	char *addr_delim;
+	int addr_len;
+	char addr_bus[RTE_ETH_NAME_MAX_LEN];
+	char addr_dev[RTE_ETH_NAME_MAX_LEN];
+
+	RTE_LOG(INFO, PMD, "Creating representor for VF %i from %s\n",
+		vport_id, pf_addr_str);
+
+	/* the parent param has to be provided with type_name formatted */
+	memset(addr_bus, 0, sizeof(addr_bus));
+	memset(addr_dev, 0, sizeof(addr_dev));
+	addr_delim = strchr(pf_addr_str, '_');
+	if (addr_delim) {
+		addr_len = addr_delim - pf_addr_str;
+		strncpy(addr_bus, pf_addr_str, addr_len);
+		strncpy(addr_dev, addr_delim + 1,
+			strlen(pf_addr_str) - addr_len);
+	} else {
+		RTE_LOG(ERR, PMD, "parent address '%s' has invalid format\n",
+			pf_addr_str);
+		return -EINVAL;
+	}
+
+	/* Fetch broker for PF */
+	broker = rte_representor_broker_find(addr_bus, addr_dev);
+	if (broker == NULL) {
+		RTE_LOG(ERR, PMD, "Unable to find broker for %s on bus %s\n",
+			addr_dev, addr_bus);
+		return -EINVAL;
+	}
+
+	/* Fetch representor slot for VF */
+	rep_port = representor_port_find(broker, vport_id);
+	if (rep_port == NULL) {
+		RTE_LOG(ERR, PMD, "vport_id %i exceeds number of VF ports %i",
+			vport_id, broker->nb_virtual_ports);
+		return -EINVAL;
+	}
+	if (rep_port->state == RTE_REPRESENTOR_PORT_VALID)
+		return -EEXIST;
+
+	/* Create representor ethdev */
+	len_name = snprintf(str_device_name, RTE_ETH_NAME_MAX_LEN, "%s.%s.%i",
+		RTE_PORT_REPRESENTOR_DEVICE_NAME, addr_dev, vport_id);
+	if (len_name == RTE_ETH_NAME_MAX_LEN) {
+		RTE_LOG(ERR, PMD, "Port Representor name"
+			" exceeds RTE_ETH_NAME_MAX_LEN\n");
+		return -EIO;
+	}
+	RTE_LOG(INFO, PMD, "Port Representor ethdev name: %s\n",
+		str_device_name);
+	rep_ethdev = rte_eth_dev_allocate(str_device_name);
+	if (rep_ethdev == NULL) {
+		RTE_LOG(ERR, PMD, "Unable to allocate Port Representor"
+			" ethdev\n");
+		return -ENOMEM;
+	}
+	rep_ethdev->data->mac_addrs = rte_malloc("representor_port_mac_addrs",
+			sizeof(struct ether_addr), 0);
+	if (rep_ethdev->data->mac_addrs == NULL) {
+		RTE_LOG(ERR, PMD, "Unable to allocate Port Representor"
+			" mac_addrs\n");
+		rte_eth_dev_release_port(rep_ethdev);
+		return -ENOMEM;
+	}
+
+	/* Allocate private ethdev data for Port Representor info */
+	rep_ethdev->data->dev_private = rte_malloc("rte_representor_port",
+			sizeof(struct rte_representor_port), 0);
+	if (rep_ethdev == NULL) {
+		RTE_LOG(ERR, PMD, "Unable to allocate Port Representor"
+			" private ethdev data\n");
+		rte_eth_dev_release_port(rep_ethdev);
+		return -ENOMEM;
+	}
+
+	/* Allocate an rte_device & rte_driver for the ethdev. */
+	rep_port->rep_pcidev = rte_zmalloc_socket("rte_device",
+		sizeof(struct rte_device), 0, rte_socket_id());
+	if (rep_port->rep_pcidev == NULL) {
+		RTE_LOG(ERR, PMD, "Unable to allocate Port Representor"
+			" devive\n");
+		return -ENOMEM;
+	}
+	rep_port->rep_pcidrv = rte_zmalloc_socket("rte_driver",
+		sizeof(struct rte_driver), 0, rte_socket_id());
+	if (rep_port->rep_pcidrv == NULL) {
+		RTE_LOG(ERR, PMD, "Unable to allocate Port Representor"
+			" driver\n");
+		return -ENOMEM;
+	}
+	rep_port->rep_pcidrv->name = RTE_PORT_REPRESENTOR_DEVICE_NAME;
+	rep_port->rep_pcidev->driver = rep_port->rep_pcidrv;
+	rep_ethdev->device = rep_port->rep_pcidev;
+
+	/* Register representor with broker */
+	RTE_REPRESENTOR_PORT_VALID_ETHDEV_OR_RET_ERR(rep_ethdev, -EINVAL);
+	rep_port->vport_id = vport_id;
+	rep_port->ethdev = rep_ethdev;
+	rep_port->broker = broker;
+	rep_port->state = RTE_REPRESENTOR_PORT_VALID;
+	rep_ethdev->data->dev_private = rep_port;
+
+	RTE_FUNC_PTR_OR_ERR_RET(broker->ops->port_init, -ENOTSUP);
+	retval = broker->ops->port_init(broker, rep_ethdev);
+	if (retval) {
+		rte_eth_dev_release_port(rep_ethdev);
+		return retval;
+	}
+	RTE_LOG(INFO, EAL, "Registered port representor "
+			"<broker=%s_%s, vport_id=%u>\n",
+			broker->bus, broker->device, vport_id);
+
+	*port_id = rep_ethdev->data->port_id;
+	return 0;
+}
+
+int
+rte_representor_port_unregister(char *pf_addr_str, uint32_t vport_id)
+{
+	struct rte_representor_port *rep_port;
+	struct rte_representor_broker *broker;
+	char *addr_delim;
+	char addr_bus[RTE_ETH_NAME_MAX_LEN];
+	char addr_dev[RTE_ETH_NAME_MAX_LEN];
+	int addr_len;
+
+	RTE_LOG(INFO, PMD, "Deleting representor for VF %i from %s\n",
+		vport_id, pf_addr_str);
+
+	/* The parent param has to be provided with type_name formatted */
+	memset(addr_bus, 0, sizeof(addr_bus));
+	memset(addr_dev, 0, sizeof(addr_dev));
+	addr_delim = strchr(pf_addr_str, '_');
+	if (addr_delim) {
+		addr_len = addr_delim - pf_addr_str;
+		strncpy(addr_bus, pf_addr_str, addr_len);
+		strncpy(addr_dev, addr_delim + 1,
+			strlen(pf_addr_str) - addr_len);
+	} else {
+		RTE_LOG(ERR, PMD, "Parent address '%s' has invalid format\n",
+			pf_addr_str);
+		return -EINVAL;
+	}
+
+	/* Fetch broker for PF */
+	broker = rte_representor_broker_find(addr_bus, addr_dev);
+	if (broker == NULL) {
+		RTE_LOG(ERR, PMD, "Unable to find broker for %s on bus %s\n",
+			addr_dev, addr_bus);
+		return -EINVAL;
+	}
+
+	/* Fetch representor slot for VF */
+	rep_port = representor_port_find(broker, vport_id);
+	if (rep_port == NULL) {
+		RTE_LOG(ERR, PMD, "Unable to fetch Port Representor handle\n");
+		return -EINVAL;
+	}
+	if (rep_port->state != RTE_REPRESENTOR_PORT_VALID) {
+		RTE_LOG(ERR, PMD, "Representor vport %i is not active\n",
+			vport_id);
+		return -EINVAL;
+	}
+
+	/* Free up representor */
+	RTE_FUNC_PTR_OR_ERR_RET(rep_port->broker->ops->port_uninit, -ENOTSUP);
+	rep_port->broker->ops->port_uninit(rep_port->broker, rep_port->ethdev);
+	rep_port->state = RTE_REPRESENTOR_PORT_INVALID;
+	rte_eth_dev_release_port(rep_port->ethdev);
+
+	/* Cannot pass the pointers ethdev->device & ethdev->device->driver to
+	 * rte_free() so have to store the allocated pointers in separate
+	 * non-const variables.
+	 */
+	rte_free(rep_port->rep_pcidrv);
+	rte_free(rep_port->rep_pcidev);
+
+	return 0;
+}
+
+int
+rte_representor_port_get_vport_id(struct rte_eth_dev *ethdev)
+{
+	struct rte_representor_port *port;
+
+	RTE_REPRESENTOR_PORT_VALID_ETHDEV_OR_RET_ERR(ethdev, -EINVAL);
+
+	port = (struct rte_representor_port *)ethdev->data->dev_private;
+
+	return port->vport_id;
+}
diff --git a/lib/librte_representor/rte_port_representor.h b/lib/librte_representor/rte_port_representor.h
new file mode 100644
index 0000000..f7903fd
--- /dev/null
+++ b/lib/librte_representor/rte_port_representor.h
@@ -0,0 +1,60 @@ 
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2017 Intel Corporation. All rights reserved.
+ */
+
+#ifndef _RTE_PORT_REPRESENTOR_H_
+#define _RTE_PORT_REPRESENTOR_H_
+
+/**
+ * @file
+ * RTE Port Representor API
+ *
+ * Driver APIs for management and support of port representor
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <rte_ethdev.h>
+#include <rte_malloc.h>
+#include <rte_flow.h>
+
+struct rte_representor_port;
+struct rte_representor_broker;
+
+/**
+ * Registers a representor ethdev with the broker, allocating a port representor
+ * context and calling the representor port initialization function.
+ *
+ * @param	pf_addr_str	Address of parent PF in Bus_DomBDF format
+ * @param	vport_id	Virtual port ID to register ethdev against
+ * @param	port_id         Pointer to integer that receives port_id
+ *
+ * @return
+ * - 0 on successful registration and initialization of representor port
+ * - errno on failure
+ */
+int
+rte_representor_port_register(char *pf_addr_str,
+		uint32_t vport_id, uint16_t *port_id);
+
+/**
+ * Unregister a representor port, called during destruction of representor
+ * ethdev context. Freeing any allocated memory for the representor port.
+ *
+ * @param	pf_addr_str	Address of parent PF in Bus_DomBDF format
+ * @param	vport_id	Virtual port ID to deregister
+ *
+ * @return
+ * - 0 on success
+ * - errno on failure
+ */
+int
+rte_representor_port_unregister(char *pf_addr_str, uint32_t vport_id);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_PORT_REPRESENTOR_H_ */
diff --git a/lib/librte_representor/rte_port_representor_driver.h b/lib/librte_representor/rte_port_representor_driver.h
new file mode 100644
index 0000000..8827ebb
--- /dev/null
+++ b/lib/librte_representor/rte_port_representor_driver.h
@@ -0,0 +1,138 @@ 
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2017 Intel Corporation. All rights reserved.
+ */
+
+#ifndef _RTE_PORT_REPRESENTOR_DRIVER_H_
+#define _RTE_PORT_REPRESENTOR_DRIVER_H_
+
+#include <rte_port_representor.h>
+
+/**
+ * @file
+ * RTE Port Representor Driver API
+ *
+ * Driver APIs for management and support of port representor
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define RTE_PORT_REPRESENTOR_DEVICE_NAME "net_representor"
+
+struct rte_representor_port;
+
+struct rte_representor_broker {
+	TAILQ_ENTRY(rte_representor_broker) next;
+	/**< Next broker object in linked list */
+
+	const char *bus;	/**< bus name */
+	const char *device;	/**< device name */
+
+	uint16_t nb_virtual_ports;
+	/**< number of virtual ports supported by device */
+
+	struct rte_representor_port *vports;
+	/**< Representor port contexts */
+
+	struct rte_representor_broker_port_ops *ops;
+	/**< broker port operations functions */
+	void *private_data;
+	/**< broker private data */
+};
+
+/** Port Representor */
+struct rte_representor_port {
+	uint16_t vport_id;
+	/**< Virtual Port Identifier */
+	struct rte_eth_dev *ethdev;
+	/**< ethdev handle of representor port */
+	struct rte_representor_broker *broker;
+	/**< Broker handle to allow reverse lookup */
+	enum {
+		RTE_REPRESENTOR_PORT_INVALID,
+		/**< No ethdev instantiated for virtual port */
+		RTE_REPRESENTOR_PORT_VALID
+		/**< ethdev active for virtual port */
+	} state;
+	/**< port state */
+	void *priv_data;
+	/**<  port private data */
+	/**< Representor ethdev device */
+	struct rte_device *rep_pcidev;
+	/**< Representor ethdev driver */
+	struct rte_driver *rep_pcidrv;
+};
+
+typedef int (*representor_broker_port_init_t)(
+		struct rte_representor_broker *broker,
+		struct rte_eth_dev *ethdev);
+
+typedef int (*representor_broker_port_uninit_t)(
+		struct rte_representor_broker *broker,
+		struct rte_eth_dev *ethdev);
+
+struct rte_representor_broker_port_ops {
+	representor_broker_port_init_t port_init;
+	representor_broker_port_init_t port_uninit;
+};
+
+/**
+ * Initialize port representor broker
+ *
+ * This function is called by the PMDs initialization routine if the port
+ * representor is enabled by EAL command line argument.
+ *
+ * Verifies broker context parameters and initialises required resources.
+ *
+ * @param	broker		port representor broker context
+ *
+ * @return
+ * - 0 on success
+ * - errno on failure
+ */
+int
+rte_representor_broker_init(struct rte_representor_broker *broker);
+
+/**
+ * Un-initialize the port representor broker freeing all associated resources.
+ *
+ * @param	broker		port representor broker
+ *
+ * @return
+ * - 0 on success
+ * - errno on failure
+ */
+int
+rte_representor_broker_uninit(struct rte_representor_broker *broker);
+
+/**
+ * Fetch a port representor broker
+ *
+ * @param	bus		Bus parent PF is on
+ * @param	device		Address of PF
+ *
+ * @return
+ * - Pointer to port representor broker on success
+ * - NULL on failure
+ */
+struct rte_representor_broker *
+rte_representor_broker_find(const char *bus, const char *device);
+
+/**
+ * Get the  virtual port ID of given representor port ethdev context
+ *
+ * @param	ethdev		Port representor ethdev handle
+ *
+ * @return
+ * - Virtual port ID
+ * - errno on failure
+ */
+int
+rte_representor_port_get_vport_id(struct rte_eth_dev *ethdev);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_PORT_REPRESENTOR_DRIVER_H_ */
diff --git a/lib/librte_representor/rte_port_representor_version.map b/lib/librte_representor/rte_port_representor_version.map
new file mode 100644
index 0000000..b26600c
--- /dev/null
+++ b/lib/librte_representor/rte_port_representor_version.map
@@ -0,0 +1,8 @@ 
+DPDK_18.02 {
+	global:
+
+	rte_representor_port_register;
+	rte_representor_port_unregister;
+
+	local: *;
+};
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index 6a6a745..67266bf 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -104,6 +104,7 @@  _LDLIBS-$(CONFIG_RTE_LIBRTE_EAL)            += -lrte_eal
 _LDLIBS-$(CONFIG_RTE_LIBRTE_CMDLINE)        += -lrte_cmdline
 _LDLIBS-$(CONFIG_RTE_LIBRTE_REORDER)        += -lrte_reorder
 _LDLIBS-$(CONFIG_RTE_LIBRTE_SCHED)          += -lrte_sched
+_LDLIBS-$(CONFIG_RTE_LIBRTE_REPRESENTOR)    += -lrte_representor
 
 ifeq ($(CONFIG_RTE_EXEC_ENV_LINUXAPP),y)
 _LDLIBS-$(CONFIG_RTE_LIBRTE_KNI)            += -lrte_kni