[VOL-4648] Generate basic response with ID and type for get request on devices

Change-Id: I5899ab9c2ae4449863d88439719c9cdf2036c1f7
diff --git a/README.md b/README.md
index cb0dc8c..d0457cf 100644
--- a/README.md
+++ b/README.md
@@ -9,9 +9,23 @@
 
 ![bbf-adapter-architecture](docs/images/bbf-adapter-architecture.svg)
 
-## Documentation
+## Deployment
 
-For information on how to deploy the BBF Adapter, please refer to [the docs folder](docs/deploy.md).
+For information on how to deploy the BBF Adapter, please refer to [deploy.md](docs/deploy.md) in the [docs](docs/README.md) folder.
+
+## Building
+
+The default credentials used to authenticate to the netopeer2 server in the BBF adapter's container are `voltha:onf`.
+
+An image with custom credentials can be built by running the following command:
+
+```
+NETCONF_USER=<username> NETCONF_PASSWORD=<password> make build
+```
+
+## Additional doucmentation
+
+Further documentation for the adapter's development can be found in the [docs](docs/README.md) folder.
 
 ## Development `make` targets
 
diff --git a/build/package/Dockerfile.bbf-adapter b/build/package/Dockerfile.bbf-adapter
index 0d8fadc..eccf3fa 100644
--- a/build/package/Dockerfile.bbf-adapter
+++ b/build/package/Dockerfile.bbf-adapter
@@ -79,7 +79,7 @@
 
 # Copy yang files and install them to sysrepo
 COPY ./build/yang-files /yang
-RUN sysrepoctl -a -i /yang/bbf-device-aggregation.yang -s /yang -p 664 -v3
+RUN for f in /yang/*.yang; do sysrepoctl -a -i "$f" -s /yang -p 664 -v3; done
 
 # Add user for connecting to netopeer2-server through ssh
 ARG NETCONF_USER=voltha
diff --git a/cmd/bbf-adapter/main.go b/cmd/bbf-adapter/main.go
index 48ac7b8..85ed990 100644
--- a/cmd/bbf-adapter/main.go
+++ b/cmd/bbf-adapter/main.go
@@ -21,16 +21,15 @@
 	"fmt"
 	"os"
 	"os/signal"
-	"sync"
 	"syscall"
 	"time"
 
-	"github.com/golang/protobuf/ptypes/empty"
 	"github.com/opencord/voltha-lib-go/v7/pkg/log"
 	"github.com/opencord/voltha-lib-go/v7/pkg/probe"
 	"github.com/opencord/voltha-lib-go/v7/pkg/version"
 	"github.com/opencord/voltha-northbound-bbf-adapter/internal/clients"
 	"github.com/opencord/voltha-northbound-bbf-adapter/internal/config"
+	"github.com/opencord/voltha-northbound-bbf-adapter/internal/core"
 	"github.com/opencord/voltha-northbound-bbf-adapter/internal/sysrepo"
 )
 
@@ -53,7 +52,7 @@
 	}
 }
 
-func (a *bbfAdapter) start(ctx context.Context, wg *sync.WaitGroup) {
+func (a *bbfAdapter) start(ctx context.Context) {
 	var err error
 
 	//Connect to the voltha northbound api
@@ -72,6 +71,9 @@
 		probe.UpdateStatusFromContext(ctx, a.conf.OnosRestEndpoint, probe.ServiceStatusRunning)
 	}
 
+	//Create the global adapter that will be used by callbacks
+	core.AdapterInstance = core.NewVolthaYangAdapter(a.volthaNbiClient, a.oltAppClient)
+
 	//Load sysrepo plugin
 	a.sysrepoPlugin, err = sysrepo.StartNewPlugin(ctx)
 	if err != nil {
@@ -80,56 +82,23 @@
 		probe.UpdateStatusFromContext(ctx, sysrepoService, probe.ServiceStatusRunning)
 	}
 
-	//Run the main logic of the BBF adapter
-
 	//Set the service as running, making the adapter finally ready
 	probe.UpdateStatusFromContext(ctx, bbfAdapterService, probe.ServiceStatusRunning)
 	logger.Info(ctx, "bbf-adapter-ready")
-
-loop:
-	for {
-		select {
-		case <-ctx.Done():
-			logger.Info(ctx, "stop-for-context-done")
-			break loop
-		case <-time.After(15 * time.Second):
-			//TODO: this is just to test functionality
-
-			//Make a request to voltha
-			devices, err := a.volthaNbiClient.Service.ListDevices(ctx, &empty.Empty{})
-			if err != nil {
-				logger.Errorw(ctx, "failed-to-list-devices", log.Fields{"err": err})
-				continue
-			}
-			logger.Debugw(ctx, "Got devices from VOLTHA", log.Fields{"devNum": len(devices.Items)})
-
-			//Make a request to Olt app
-			response, err := a.oltAppClient.GetStatus()
-			if err != nil {
-				logger.Errorw(ctx, "failed-to-get-status", log.Fields{
-					"err":     err,
-					"reponse": response,
-				})
-				continue
-			} else {
-				logger.Debugw(ctx, "Got status from OltApp", log.Fields{"response": response})
-			}
-
-			logger.Warn(ctx, "BBF Adapter currently has no implemented logic.")
-		}
-	}
-
-	probe.UpdateStatusFromContext(ctx, bbfAdapterService, probe.ServiceStatusStopped)
-	wg.Done()
 }
 
 //Close all connections of the adapter
 func (a *bbfAdapter) cleanup(ctx context.Context) {
+	core.AdapterInstance = nil
+
 	a.volthaNbiClient.Close(ctx)
+
 	err := a.sysrepoPlugin.Stop(ctx)
 	if err != nil {
 		logger.Errorw(ctx, "failed-to-stop-sysrepo-plugin", log.Fields{"err": err})
 	}
+
+	probe.UpdateStatusFromContext(ctx, bbfAdapterService, probe.ServiceStatusStopped)
 }
 
 func printBanner() {
@@ -245,9 +214,7 @@
 	adapter := newBbfAdapter(conf)
 
 	//Run the adapter
-	wg := &sync.WaitGroup{}
-	wg.Add(1)
-	go adapter.start(probeCtx, wg)
+	adapter.start(probeCtx)
 	defer adapter.cleanup(probeCtx)
 
 	//Wait a signal to stop execution
@@ -256,8 +223,6 @@
 
 	//Stop everything that waits for the context to be done
 	cancelCtx()
-	//Wait for the adapter logic to stop
-	wg.Wait()
 
 	elapsed := time.Since(start)
 	logger.Infow(ctx, "run-time", log.Fields{"time": elapsed.Seconds()})
diff --git a/docs/README.md b/docs/README.md
new file mode 100644
index 0000000..c37a0c3
--- /dev/null
+++ b/docs/README.md
@@ -0,0 +1,13 @@
+The goal of the voltha-northbound-bbf-adapter is to enable VOLTHA to be controlled through NETCONF using standard BBF yang modules. The current state of the translation between the two mainly consists in the use of the models from [TR-383](https://wiki.broadband-forum.org/display/BBF/TR-383%3A+Common+YANG+Modules+for+Access+Networks).\
+The architecture used by the adapter to achieve this involves the use of netopeer2 as a NETCONF server and sysrepo as its datastore. This configuration was proposed by BISDN, more information can be found in the [slides](https://wiki.broadband-forum.org/display/BBF/ONF+and+BBF+SEBA+Collaboration?preview=/131466119/141855024/20220309%20-%20vOLTHA%20adaption%20to%20BBF%20yang%20models.pptx).
+
+On its northbound, the BBF adapter interacts with sysrepo by acting as a plugin, using the APIs of libsysrepo.
+Instead, on its southbound, it interacts with VOLTHA's northbound APIs and the Olt ONOS app REST APIs to collect data and perform commands.
+
+![bbf-adapter-architecture](images/bbf-adapter-architecture.svg)
+
+# Additional documentation
+
+- [Deployment](deploy.md)
+- [Code structure](code_structure.md)
+- [Expanding functionality](expanding.md)
\ No newline at end of file
diff --git a/docs/code_structure.md b/docs/code_structure.md
new file mode 100644
index 0000000..4eb3e0d
--- /dev/null
+++ b/docs/code_structure.md
@@ -0,0 +1,46 @@
+# BBF Adapter code structure
+
+## `build` directory and Docker images
+
+The `build` directory contains the files used for the creation of a voltha-northbound-bbf-adapter Docker image that can be used for deployment.
+
+- `build/tools` contains the Dockerfile of the "builder" image. This image includes a golang toolchain and the .deb packages for libyang and sysrepo.\
+The presence of these packages allows the correct compilation of the project, which would otherwise fail due to missing dependencies. The same image is used for linting and testing through the Makefile.
+- `build/package` contains the Dockerfile of the actual BBF adapter image. It uses the builder image to compile the code of this repository. The generated binaries are then copied on the production image, where packages for libyang, sysrepo and netopeer2 are installed.\
+During this step, the yang files in `build/yang-files` are installed with sysrepoctl, making them available at runtime.\
+A user account that can be used to log in to netopeer2 is also created at this time. The credentials of this user can be changed by setting the `NETCONF_USER` and `NETCONF_PASSWORD` arguments.
+
+When the adapter image is deployed with the `onf/voltha-northbound-bbf-adapter` helm chart defined in [voltha-helm-charts](https://github.com/opencord/voltha-helm-charts), netopeer2 is automatically started with the `netopeer2-server` command before running the adapter itself.
+
+## `cmd` directory
+
+The `cmd/bbf-adapter` directory contains the source for the main function of the adapter.\
+`main.go` loads the configuration provided through CLI flags by the user, starts all the necessary components defined in the `internal` directory, keeps track of the adapter's readiness status and exposes it through the probe package of voltha-lib-go.
+
+## `internal` directory
+
+The `interal` directory contains the remaining logic of the adapter, split in multiple packages.
+
+### `internal/clients`
+
+This package contains the implementation of clients that the adapter can use to interact with the VOLTHA components that are necessary to provide its funcionality.
+-  `nbi.go` provides a connection to VOLTHA's "northbound interface" gRPC service, which can be used to interact with the core the same way a user would using voltctl. This client can be used to list the devices, provision a new OLT and enable it.
+- `olt_app.go` provides wrapper functions for the REST APIs exposed by the Olt ONOS application. This client can be used to provision a subscriber on a specific device and port.
+
+### `internal/config`
+
+This package contains the definition of CLI flags that can be used to configure the adapter's behavior, and their default values.
+
+### `interal/core`
+
+This package contains the implementation of the VolthaYangAdapter (`adapter.go`), an instance of which is exposed globally as core.AdapterInstance. This is necessary because the callback functions defined in `internal/sysrepo/syrepo.go` would have no other way to reference it when being called from sysrepo.\
+VolthaYangAdapter provides methods to perform actions through its clients or request data from them. In the latter case, the functions defined in `translation.go` are used to translate information to a set of yang paths and values that will be used to update the NETCONF datastore.
+
+### `internal/sysrepo`
+
+Since sysrepo doesn't provide official bindings for golang, this project uses CGO to interact with sysrepo through its official C library: libsysrepo.
+
+- `plugin.c` is a C file used to include dependencies (like libyang and sysrepo header files) and define some utilities that make it possible to perform all the necessary operations through CGO.
+- `sysrepo.go` imports `plugin.c` and defines the SysrepoPlugin struct, which keeps track of the adapter's connection with sysrepo. At startup, a connection is created and the necessary callback functions are registered.
+
+When a NETCONF operation is executed on one of the modules managed by the BBF adapter, the corresponding go function will be called. The latter will interact with the global instance of VolthaYangAdapter to fulfill the request and provide a result, eventually updating the content of the datastore.
\ No newline at end of file
diff --git a/docs/deploy.md b/docs/deploy.md
index 44f5a3a..0f80c77 100644
--- a/docs/deploy.md
+++ b/docs/deploy.md
@@ -13,7 +13,7 @@
 
 ```
 helm upgrade --install --create-namespace -n voltha bbf \
-            onf/voltha-northbound-bbf-adapter/ --devel \
+            onf/voltha-northbound-bbf-adapter --devel \
             --set global.voltha_infra_name=voltha-infra \
             --set global.voltha_infra_namespace=infra \
             --set global.voltha_stack_name=voltha \
@@ -54,11 +54,9 @@
 After a successful login, a request can be performed:
 
 ```
-get-data --datastore operational --filter-xpath /bbf-device-aggregation:devices
+get-data --datastore operational --filter-xpath /bbf-device-aggregation:*
 ```
 
-The adapter doesn't perform request translations yet, but the success of the operation can be inferred by looking at the container's logs, which will show a `>>>>>>>RECEIVED REQUEST FROM SYSREPO<<<<<<<` message.
-
 ## Stop the BBF adapter
 ```
 helm delete -n voltha bbf
diff --git a/docs/expanding.md b/docs/expanding.md
new file mode 100644
index 0000000..eb7b773
--- /dev/null
+++ b/docs/expanding.md
@@ -0,0 +1,14 @@
+# Expanding the adapter's functionality
+
+## Resources
+- [libsysrepo API documentation](https://netopeer.liberouter.org/doc/sysrepo/master/html/modules.html)
+- [libyang API documentation](https://netopeer.liberouter.org/doc/libyang/master/html/modules.html)
+
+## How to expand the adapter's functionality by creating new callbacks
+
+- If additional yang modules are needed, add them to `build/yang-files` to be installed to sysrepo during the creation of the adapter's Docker image
+- A new callback function has to be created. CGO cannot directly express the `const` keyword used in the signature of the C callbacks of libsysrepo.\
+For this reason, a Go function can be created and exposed in `internal/sysrepo/sysrepo.go`, while its corresponding wrapper with the right signature has to be created in `internal/sysrepo/plugin.go`.
+- The new callback wrapper has to be registered in the StartNewPlugin function of `internal/sysrepo/sysrepo.go`, using the sysrepo API to subscribe to the desired type of operation and XPath.
+- The Golang callback will interact with VOLTHA through the instance of VolthaYangAdapter exposed by the `core.AdapterInstance` variable.\
+If the operation needed by the new callback is not implemented already, it can be created as a new method in `internal/core/adapter.go`, eventually expanding the capabilities of the clients in `internal/clients/nbi.go` and `internal/clients/olt_app.go`, or creating new translation functions in `internal/core/translation.go`.
\ No newline at end of file
diff --git a/internal/core/adapter.go b/internal/core/adapter.go
new file mode 100644
index 0000000..a96767f
--- /dev/null
+++ b/internal/core/adapter.go
@@ -0,0 +1,54 @@
+/*
+* Copyright 2022-present Open Networking Foundation
+
+* 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.
+ */
+
+package core
+
+import (
+	"context"
+	"fmt"
+
+	"github.com/golang/protobuf/ptypes/empty"
+	"github.com/opencord/voltha-lib-go/v7/pkg/log"
+	"github.com/opencord/voltha-northbound-bbf-adapter/internal/clients"
+)
+
+var AdapterInstance *VolthaYangAdapter
+
+type VolthaYangAdapter struct {
+	volthaNbiClient *clients.VolthaNbiClient
+	oltAppClient    *clients.OltAppClient
+}
+
+func NewVolthaYangAdapter(nbiClient *clients.VolthaNbiClient, oltClient *clients.OltAppClient) *VolthaYangAdapter {
+	return &VolthaYangAdapter{
+		volthaNbiClient: nbiClient,
+		oltAppClient:    oltClient,
+	}
+}
+
+func (t *VolthaYangAdapter) GetDevices(ctx context.Context) ([]YangItem, error) {
+	devices, err := t.volthaNbiClient.Service.ListDevices(ctx, &empty.Empty{})
+	if err != nil {
+		err = fmt.Errorf("get-devices-failed: %v", err)
+		return nil, err
+	}
+
+	items := translateDevices(*devices)
+
+	logger.Debugw(ctx, "get-devices-success", log.Fields{"items": items})
+
+	return items, nil
+}
diff --git a/internal/core/logger.go b/internal/core/logger.go
new file mode 100644
index 0000000..0aa6eef
--- /dev/null
+++ b/internal/core/logger.go
@@ -0,0 +1,32 @@
+/*
+* Copyright 2022-present Open Networking Foundation
+
+* 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.
+ */
+
+package core
+
+import (
+	"github.com/opencord/voltha-lib-go/v7/pkg/log"
+)
+
+var logger log.CLogger
+
+func init() {
+	// Setup this package so that it's log level can be modified at run time
+	var err error
+	logger, err = log.RegisterPackage(log.JSON, log.ErrorLevel, log.Fields{})
+	if err != nil {
+		panic(err)
+	}
+}
diff --git a/internal/core/translation.go b/internal/core/translation.go
new file mode 100644
index 0000000..bc7c692
--- /dev/null
+++ b/internal/core/translation.go
@@ -0,0 +1,67 @@
+/*
+* Copyright 2022-present Open Networking Foundation
+
+* 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.
+ */
+
+package core
+
+import (
+	"fmt"
+
+	"github.com/opencord/voltha-protos/v5/go/voltha"
+)
+
+const (
+	DeviceAggregationModel = "bbf-device-aggregation"
+	DevicesPath            = "/" + DeviceAggregationModel + ":devices"
+	DeviceTypeOlt          = "bbf-device-types:olt"
+	DeviceTypeOnu          = "bbf-device-types:onu"
+)
+
+type YangItem struct {
+	Path  string
+	Value string
+}
+
+//getDevicePath returns the yang path to the root of the device with a specific ID
+func getDevicePath(id string) string {
+	return fmt.Sprintf("%s/device[name='%s']", DevicesPath, id)
+}
+
+//translateDevice returns a slice of yang items that represent a voltha device
+func translateDevice(device voltha.Device) []YangItem {
+	devicePath := getDevicePath(device.Id)
+
+	typeItem := YangItem{}
+	typeItem.Path = fmt.Sprintf("%s/type", devicePath)
+
+	if device.Root {
+		typeItem.Value = DeviceTypeOlt
+	} else {
+		typeItem.Value = DeviceTypeOnu
+	}
+
+	return []YangItem{typeItem}
+}
+
+//translateDevices returns a slice of yang items that represent a list of voltha devices
+func translateDevices(devices voltha.Devices) []YangItem {
+	result := []YangItem{}
+
+	for _, device := range devices.Items {
+		result = append(result, translateDevice(*device)...)
+	}
+
+	return result
+}
diff --git a/internal/core/translation_test.go b/internal/core/translation_test.go
new file mode 100644
index 0000000..fb2e751
--- /dev/null
+++ b/internal/core/translation_test.go
@@ -0,0 +1,101 @@
+/*
+* Copyright 2022-present Open Networking Foundation
+
+* 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.
+ */
+
+package core
+
+import (
+	"fmt"
+	"testing"
+
+	"github.com/opencord/voltha-protos/v5/go/voltha"
+	"github.com/stretchr/testify/assert"
+)
+
+const (
+	testDeviceId = "123145abcdef"
+)
+
+func getItemWithPath(items []YangItem, path string) (value string, ok bool) {
+	for _, item := range items {
+		if item.Path == path {
+			return item.Value, true
+		}
+	}
+
+	return "", false
+}
+
+func TestDevicePath(t *testing.T) {
+	path := getDevicePath(testDeviceId)
+	assert.Equal(t, fmt.Sprintf("/bbf-device-aggregation:devices/device[name='%s']", testDeviceId), path)
+}
+
+func TestTranslateDevice(t *testing.T) {
+	olt := voltha.Device{
+		Id:   testDeviceId,
+		Root: true,
+	}
+	items := translateDevice(olt)
+
+	val, ok := getItemWithPath(items, fmt.Sprintf("%s/type", getDevicePath(testDeviceId)))
+	assert.True(t, ok, "No type item for olt")
+	assert.Equal(t, DeviceTypeOlt, val)
+
+	onu := voltha.Device{
+		Id:   testDeviceId,
+		Root: false,
+	}
+	items = translateDevice(onu)
+
+	val, ok = getItemWithPath(items, fmt.Sprintf("%s/type", getDevicePath(testDeviceId)))
+	assert.True(t, ok, "No type item for onu")
+	assert.Equal(t, DeviceTypeOnu, val)
+}
+
+func TestTranslateDevices(t *testing.T) {
+	devicesNum := 10
+
+	//Create test devices
+	devices := voltha.Devices{
+		Items: []*voltha.Device{},
+	}
+
+	for i := 0; i < devicesNum; i++ {
+		devices.Items = append(devices.Items, &voltha.Device{
+			Id:   fmt.Sprintf("%d", i),
+			Root: i%2 == 0,
+		})
+	}
+
+	//Translate them to items
+	items := translateDevices(devices)
+
+	//Check if the number of generated items is correct
+	singleDeviceItemsNum := len(translateDevice(*devices.Items[0]))
+	assert.Equal(t, singleDeviceItemsNum*devicesNum, len(items))
+
+	//Check if the content is right
+	for i := 0; i < devicesNum; i++ {
+		val, ok := getItemWithPath(items, fmt.Sprintf("%s/type", getDevicePath(devices.Items[i].Id)))
+		assert.True(t, ok, fmt.Sprintf("No type item for device %d", i))
+
+		if devices.Items[i].Root {
+			assert.Equal(t, DeviceTypeOlt, val)
+		} else {
+			assert.Equal(t, DeviceTypeOnu, val)
+		}
+	}
+}
diff --git a/internal/sysrepo/plugin.c b/internal/sysrepo/plugin.c
index edbf0e5..f3ff6a3 100644
--- a/internal/sysrepo/plugin.c
+++ b/internal/sysrepo/plugin.c
@@ -14,16 +14,22 @@
 * limitations under the License.
  */
 
+#include <libyang/libyang.h>
 #include <sysrepo.h>
 #include <sysrepo/xpath.h>
 
 //Needed to handle callback functions with a working data type in CGO
 typedef void (*function)(); // https://golang.org/issue/19835
 
-//Exported by sysrepo.go
-void get_data_cb();
+//CGO can't see raw structs
+typedef struct lyd_node lyd_node;
 
-int get_data_cb_wrapper(
+//Exported by sysrepo.go
+sr_error_t get_devices_cb(sr_session_ctx_t *session, lyd_node **parent);
+
+//The wrapper function is needed because CGO cannot express const char*
+//and thus it can't match sysrepo's callback signature
+int get_devices_cb_wrapper(
     sr_session_ctx_t *session,
     uint32_t subscription_id,
     const char *module_name,
@@ -33,7 +39,5 @@
     struct lyd_node **parent,
     void *private_data)
 {
-    get_data_cb();
-
-    return SR_ERR_OK;
+    return get_devices_cb(session, parent);
 }
\ No newline at end of file
diff --git a/internal/sysrepo/sysrepo.go b/internal/sysrepo/sysrepo.go
index b0ebc1f..57de757 100644
--- a/internal/sysrepo/sysrepo.go
+++ b/internal/sysrepo/sysrepo.go
@@ -17,19 +17,16 @@
 package sysrepo
 
 //#cgo CFLAGS: -I/usr/include
-//#cgo LDFLAGS: -lsysrepo -Wl,--allow-multiple-definition
+//#cgo LDFLAGS: -lsysrepo -lyang -Wl,--allow-multiple-definition
 //#include "plugin.c"
 import "C"
 import (
 	"context"
 	"fmt"
+	"unsafe"
 
 	"github.com/opencord/voltha-lib-go/v7/pkg/log"
-)
-
-const (
-	BASE_YANG_MODEL    = "bbf-device-aggregation"
-	DEVICES_YANG_MODEL = "/" + BASE_YANG_MODEL + ":devices"
+	"github.com/opencord/voltha-northbound-bbf-adapter/internal/core"
 )
 
 type SysrepoPlugin struct {
@@ -42,10 +39,48 @@
 	return C.GoString(C.sr_strerror(code))
 }
 
+func freeCString(str *C.char) {
+	if str != nil {
+		C.free(unsafe.Pointer(str))
+		str = nil
+	}
+}
+
+func updateYangItems(ctx context.Context, session *C.sr_session_ctx_t, parent **C.lyd_node, items []core.YangItem) error {
+	conn := C.sr_session_get_connection(session)
+	if conn == nil {
+		return fmt.Errorf("null-connection")
+	}
+
+	//libyang context
+	ly_ctx := C.sr_get_context(conn)
+	if ly_ctx == nil {
+		return fmt.Errorf("null-libyang-context")
+	}
+
+	for _, item := range items {
+		logger.Debugw(ctx, "updating-yang-item", log.Fields{"item": item})
+
+		path := C.CString(item.Path)
+		value := C.CString(item.Value)
+
+		lyErr := C.lyd_new_path(*parent, ly_ctx, path, value, 0, nil)
+		if lyErr != C.LY_SUCCESS {
+			freeCString(path)
+			freeCString(value)
+			return fmt.Errorf("libyang-new-path-failed: %d", lyErr)
+		}
+
+		freeCString(path)
+		freeCString(value)
+	}
+
+	return nil
+}
+
 //createPluginState populates a SysrepoPlugin struct by establishing
 //a connection and a session
 func (p *SysrepoPlugin) createSession(ctx context.Context) error {
-
 	var errCode C.int
 
 	//Populates connection
@@ -70,17 +105,42 @@
 	return nil
 }
 
-//export get_data_cb
-func get_data_cb() {
-	//This function is a callback for the retrieval of data from sysrepo
+//export get_devices_cb
+func get_devices_cb(session *C.sr_session_ctx_t, parent **C.lyd_node) C.sr_error_t {
+	//This function is a callback for the retrieval of devices from sysrepo
 	//The "export" comment instructs CGO to create a C function for it
 
-	//As a placeholder, it just reports that a request to get data
-	//has been received from the netconf server
-
-	//TODO: get actual information
 	ctx := context.Background()
-	logger.Info(ctx, ">>>>>>>RECEIVED REQUEST FROM SYSREPO<<<<<<<")
+	logger.Debug(ctx, "processing-get-data-request")
+
+	if session == nil {
+		logger.Error(ctx, "sysrepo-get-data-null-session")
+		return C.SR_ERR_OPERATION_FAILED
+	}
+
+	if parent == nil {
+		logger.Error(ctx, "sysrepo-get-data-null-parent-node")
+		return C.SR_ERR_OPERATION_FAILED
+	}
+
+	if core.AdapterInstance == nil {
+		logger.Error(ctx, "sysrepo-get-data-nil-translator")
+		return C.SR_ERR_OPERATION_FAILED
+	}
+
+	devices, err := core.AdapterInstance.GetDevices(ctx)
+	if err != nil {
+		logger.Errorw(ctx, "sysrepo-get-data-translator-error", log.Fields{"err": err})
+		return C.SR_ERR_OPERATION_FAILED
+	}
+
+	err = updateYangItems(ctx, session, parent, devices)
+	if err != nil {
+		logger.Errorw(ctx, "sysrepo-get-data-update-error", log.Fields{"err": err})
+		return C.SR_ERR_OPERATION_FAILED
+	}
+
+	return C.SR_ERR_OK
 }
 
 func StartNewPlugin(ctx context.Context) (*SysrepoPlugin, error) {
@@ -98,11 +158,17 @@
 	//Set callbacks for events
 
 	//Subscribe with a callback to the request of data on a certain path
+	module := C.CString(core.DeviceAggregationModel)
+	defer freeCString(module)
+
+	path := C.CString(core.DevicesPath + "/*")
+	defer freeCString(path)
+
 	errCode := C.sr_oper_get_items_subscribe(
 		plugin.session,
-		C.CString(BASE_YANG_MODEL),
-		C.CString(DEVICES_YANG_MODEL+"/*"),
-		C.function(C.get_data_cb_wrapper),
+		module,
+		path,
+		C.function(C.get_devices_cb_wrapper),
 		C.NULL,
 		C.SR_SUBSCR_CTX_REUSE,
 		&plugin.subscription,