diff --git a/scripts/run_tests_locally-telemetry-gnmi.sh b/scripts/run_tests_locally-telemetry-gnmi.sh
new file mode 100755
index 0000000000000000000000000000000000000000..3c7630edae762c5279a1c4b41cdd14a10748803c
--- /dev/null
+++ b/scripts/run_tests_locally-telemetry-gnmi.sh
@@ -0,0 +1,29 @@
+#!/bin/bash
+# Copyright 2022-2024 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/)
+#
+# 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.
+
+
+PROJECTDIR=`pwd`
+
+cd $PROJECTDIR/src
+# RCFILE=$PROJECTDIR/coverage/.coveragerc
+
+# export KFK_SERVER_ADDRESS='127.0.0.1:9092'
+# CRDB_SQL_ADDRESS=$(kubectl get service cockroachdb-public --namespace crdb -o jsonpath='{.spec.clusterIP}')
+# export CRDB_URI="cockroachdb://tfs:tfs123@${CRDB_SQL_ADDRESS}:26257/tfs_telemetry?sslmode=require"
+RCFILE=$PROJECTDIR/coverage/.coveragerc
+
+python3 -m pytest --log-level=debug --log-cli-level=info --verbose \
+    telemetry/backend/tests/test_gnmi_collector.py
+
diff --git a/src/telemetry/backend/collector_api/_Collector.py b/src/telemetry/backend/collector_api/_Collector.py
index ec4ba943c90de8a8d683d1e7a9dd9d48865b5edf..521e053d7f5a90773f3a9175fbf4c58c67286ebb 100644
--- a/src/telemetry/backend/collector_api/_Collector.py
+++ b/src/telemetry/backend/collector_api/_Collector.py
@@ -135,26 +135,20 @@ class _Collector:
         """
         raise NotImplementedError()
 
-    def SubscribeState(self, subscriptions: List[Tuple[str, float, float]]) -> \
+    def SubscribeState(self, subscriptions: List[Tuple[str, dict, float, float]]) -> \
+                List[Union[bool, Exception]]:
+        """ Subscribe to state information of the entire device or selected resources. 
+            Subscriptions are incremental, and the collector should keep track of requested resources.
+                    List of tuples, each containing:
+                        - resource_id (str): Identifier pointing to the resource to be subscribed.
+                        - resource_dict (dict): Dictionary containing resource name, KPI to be subscribed, and type.
+                        - sampling_duration (float): Duration (in seconds) for how long monitoring should last.
+                        - sampling_interval (float): Desired monitoring interval (in seconds) for the specified resource.
+                    List of results for the requested resource key subscriptions. 
+                    The return values are in the same order as the requested resource keys.
+                    - True if a resource is successfully subscribed.
+                    - Exception if an error occurs during the subscription process.
             List[Union[bool, Exception]]:
-        """ Subscribe to state information of entire device or
-        selected resources. Subscriptions are incremental.
-            Collector should keep track of requested resources.
-            Parameters:
-                subscriptions : List[Tuple[str, float, float]]
-                    List of tuples, each containing a resource_key pointing the
-                    resource to be subscribed, a sampling_duration, and a
-                    sampling_interval (both in seconds with float
-                    representation) defining, respectively, for how long
-                    monitoring should last, and the desired monitoring interval
-                    for the resource specified.
-            Returns:
-                results : List[Union[bool, Exception]]
-                    List of results for resource key subscriptions requested.
-                    Return values must be in the same order as the resource keys
-                    requested. If a resource is properly subscribed,
-                    True must be retrieved; otherwise, the Exception that is
-                    raised during the processing must be retrieved.
         """
         raise NotImplementedError()
 
diff --git a/src/telemetry/backend/collectors/gnmi_openconfig/Acknowledgement.txt b/src/telemetry/backend/collectors/gnmi_openconfig/Acknowledgement.txt
new file mode 100644
index 0000000000000000000000000000000000000000..a004e1f58bdea3ba78263a06e6e473f593e1b390
--- /dev/null
+++ b/src/telemetry/backend/collectors/gnmi_openconfig/Acknowledgement.txt
@@ -0,0 +1,25 @@
+This code is partially based on:
+https://github.com/nokia/pygnmi/blob/master/gNMI_Subscribe.py
+
+
+MIT License
+
+Copyright (c) 2017 Nokia
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
\ No newline at end of file
diff --git a/src/telemetry/backend/collectors/gnmi_openconfig/GnmiOpenConfigCollector.py b/src/telemetry/backend/collectors/gnmi_openconfig/GnmiOpenConfigCollector.py
new file mode 100644
index 0000000000000000000000000000000000000000..b318ae1d870c4b6ca7abc7c12a651423f71d3f8d
--- /dev/null
+++ b/src/telemetry/backend/collectors/gnmi_openconfig/GnmiOpenConfigCollector.py
@@ -0,0 +1,81 @@
+# Copyright 2022-2024 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/)
+#
+# 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.
+
+import logging, queue, threading
+from typing import Any, Iterator, List, Optional, Tuple, Union
+from common.method_wrappers.Decorator import MetricsPool, metered_subclass_method
+from common.type_checkers.Checkers import chk_type
+from telemetry.backend.collector_api._Collector import _Collector
+from .GnmiSessionHandler import GnmiSessionHandler
+
+COLLECTOR_NAME = 'gnmi_openconfig'
+METRICS_POOL   = MetricsPool('Telemtery', 'Collectors', labels={'collector': COLLECTOR_NAME})
+
+class GnmiOpenConfigCollector(_Collector):
+    def __init__(self, address : str, port : int, **settings) -> None:
+        super().__init__(COLLECTOR_NAME, address, port, **settings)
+        self.__logger      = logging.getLogger('{:s}:[{:s}:{:s}]'.format(str(__name__), str(self.address), str(self.port)))
+        self.__lock        = threading.Lock()
+        self.__started     = threading.Event()
+        self.__terminate   = threading.Event()
+        self.__handler     = GnmiSessionHandler(self.address, self.port, settings, self.__logger)
+        self.__out_samples = self.__handler.out_samples
+
+    def Connect(self) -> bool:
+        with self.__lock:
+            if self.__started.is_set(): return True
+            self.__handler.connect()
+            self.__started.set()
+            return True
+
+    def Disconnect(self) -> bool:
+        with self.__lock:
+            # Trigger termination of loops and processes
+            self.__terminate.set()
+            # If not started, assume it is already disconnected
+            if not self.__started.is_set(): return True
+            self.__handler.disconnect()
+            return True
+
+    @metered_subclass_method(METRICS_POOL)
+    def GetConfig(self, resource_keys : List[str] = []) -> List[Tuple[str, Union[Any, None, Exception]]]:
+        chk_type('resources', resource_keys, list)
+        with self.__lock:
+            return self.__handler.get(resource_keys)
+
+    @metered_subclass_method(METRICS_POOL)
+    def SubscribeState(self, subscriptions : List[Tuple[str, float, float]]) -> List[Union[bool, Exception]]:
+        chk_type('subscriptions', subscriptions, list)
+        if len(subscriptions) == 0: return []
+        with self.__lock:
+            return self.__handler.subscribe(subscriptions)
+
+    @metered_subclass_method(METRICS_POOL)
+    def UnsubscribeState(self, subscriptions : List[Tuple[str, float, float]]) -> List[Union[bool, Exception]]:
+        chk_type('subscriptions', subscriptions, list)
+        if len(subscriptions) == 0: return []
+        with self.__lock:
+            return self.__handler.unsubscribe(subscriptions)
+
+    def GetState(self, blocking=False, terminate : Optional[threading.Event] = None) -> Iterator[Tuple[float, str, Any]]:
+        while True:
+            if self.__terminate.is_set(): break
+            if terminate is not None and terminate.is_set(): break
+            try:
+                sample = self.__out_samples.get(block=blocking, timeout=0.1)
+            except queue.Empty:
+                if blocking: continue
+                return
+            if sample is None: continue
+            yield sample
diff --git a/src/telemetry/backend/collectors/gnmi_openconfig/GnmiSessionHandler.py b/src/telemetry/backend/collectors/gnmi_openconfig/GnmiSessionHandler.py
new file mode 100644
index 0000000000000000000000000000000000000000..825462cfbebce444cd8114e9ac5ffbbf4c0f9de6
--- /dev/null
+++ b/src/telemetry/backend/collectors/gnmi_openconfig/GnmiSessionHandler.py
@@ -0,0 +1,171 @@
+# Copyright 2022-2024 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/)
+#
+# 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.
+
+import copy, grpc, json, logging, queue, threading
+from typing import Any, Dict, List, Optional, Tuple, Union
+from common.tools.grpc.Tools import grpc_message_to_json_string
+from common.type_checkers.Checkers import chk_float, chk_length, chk_string, chk_type
+from .gnmi.gnmi_pb2_grpc import gNMIStub
+from .gnmi.gnmi_pb2 import Encoding, GetRequest
+from .handlers import ALL_RESOURCE_KEYS, compose, get_path, parse
+from .handlers.YangHandler import YangHandler
+from .tools.Capabilities import check_capabilities
+from .tools.Channel import get_grpc_channel
+from .tools.Path import path_from_string, path_to_string #, compose_path
+from .tools.Subscriptions import Subscriptions
+from .tools.Value import decode_value #, value_exists
+
+class GnmiSessionHandler:
+    def __init__(self, address : str, port : int, settings : Dict, logger : logging.Logger) -> None:
+        self._address   = address
+        self._port      = port
+        self._settings  = copy.deepcopy(settings)
+        self._logger    = logger
+        self._lock      = threading.Lock()
+        self._connected = threading.Event()
+        self._username  = settings.get('username')
+        self._password  = settings.get('password')
+        self._use_tls   = settings.get('use_tls', False)
+        self._channel : Optional[grpc.Channel] = None
+        self._stub : Optional[gNMIStub] = None
+        self._yang_handler = YangHandler()
+        self._subscriptions = Subscriptions()
+        self._in_subscriptions = queue.Queue()
+        self._out_samples = queue.Queue()
+
+    def __del__(self) -> None:
+        self._logger.info('Destroying YangValidator...')
+        if self._yang_handler is not None:
+            self._logger.debug('yang_validator.data:')
+            for path, dnode in self._yang_handler.get_data_paths().items():
+                self._logger.debug('  {:s}: {:s}'.format(str(path), json.dumps(dnode.print_dict())))
+            self._yang_handler.destroy()
+        self._logger.info('DONE')
+
+    @property
+    def subscriptions(self): return self._subscriptions
+
+    @property
+    def in_subscriptions(self): return self._in_subscriptions
+
+    @property
+    def out_samples(self): return self._out_samples
+
+    def connect(self):
+        with self._lock:
+            self._channel = get_grpc_channel(self._address, self._port, self._use_tls, self._logger)
+            self._stub = gNMIStub(self._channel)
+            check_capabilities(self._stub, self._username, self._password, timeout=120) # type: ignore
+            self._connected.set()
+
+    def disconnect(self):
+        if not self._connected.is_set(): return
+        with self._lock:
+            self._channel.close() # type: ignore
+            self._connected.clear()
+
+    def get(self, resource_keys : List[str]) -> List[Tuple[str, Union[Any, None, Exception]]]:
+        if len(resource_keys) == 0: resource_keys = ALL_RESOURCE_KEYS
+        chk_type('resources', resource_keys, list)
+
+        parsing_results = []
+
+        get_request = GetRequest()
+        get_request.type = GetRequest.DataType.ALL
+        get_request.encoding = Encoding.JSON_IETF
+        #get_request.use_models.add() # kept empty: return for all models supported
+        for i,resource_key in enumerate(resource_keys):
+            str_resource_name = 'resource_key[#{:d}]'.format(i)
+            try:
+                chk_string(str_resource_name, resource_key, allow_empty=False)
+                self._logger.debug('[GnmiSessionHandler:get] resource_key = {:s}'.format(str(resource_key)))
+                str_path = get_path(resource_key)
+                self._logger.debug('[GnmiSessionHandler:get] str_path = {:s}'.format(str(str_path)))
+                get_request.path.append(path_from_string(str_path))
+            except Exception as e: # pylint: disable=broad-except
+                MSG = 'Exception parsing {:s}: {:s}'
+                self._logger.exception(MSG.format(str_resource_name, str(resource_key)))
+                parsing_results.append((resource_key, e)) # if validation fails, store the exception
+
+        self._logger.debug('parsing_results={:s}'.format(str(parsing_results)))
+
+        if len(parsing_results) > 0:
+            return parsing_results
+
+        metadata = [('username', self._username), ('password', self._password)]
+        timeout = None # GNMI_SUBSCRIPTION_TIMEOUT = int(sampling_duration)
+        get_reply = self._stub.Get(get_request, metadata=metadata, timeout=timeout)
+        self._logger.debug('get_reply={:s}'.format(grpc_message_to_json_string(get_reply)))
+
+        results = []
+        #results[str_filter] = [i, None, False]  # (index, value, processed?)
+
+        for notification in get_reply.notification:
+            for update in notification.update:
+                self._logger.debug('update={:s}'.format(grpc_message_to_json_string(update)))
+                str_path = path_to_string(update.path)
+                try:
+                    value = decode_value(update.val)
+                    #resource_key_tuple[1] = value
+                    #resource_key_tuple[2] = True
+                    results.extend(parse(str_path, value, self._yang_handler))
+                except Exception as e: # pylint: disable=broad-except
+                    MSG = 'Exception processing update {:s}'
+                    self._logger.exception(MSG.format(grpc_message_to_json_string(update)))
+                    results.append((str_path, e)) # if validation fails, store the exception
+        return results
+
+    def subscribe(self, subscriptions : List[Tuple[str, float, float]]) -> List[Union[bool, Exception]]:
+        results = []
+        for i,subscription in enumerate(subscriptions):
+            str_subscription_name = 'subscriptions[#{:d}]'.format(i)
+            try:
+                chk_type(str_subscription_name, subscription, {list, tuple})
+                chk_length(str_subscription_name, subscription, min_length=3, max_length=3)
+                resource_key, sampling_duration, sampling_interval = subscription
+                chk_string(str_subscription_name + '.resource_key', resource_key, allow_empty=False)
+                chk_float(str_subscription_name + '.sampling_duration', sampling_duration, min_value=0)
+                chk_float(str_subscription_name + '.sampling_interval', sampling_interval, min_value=0)
+            except Exception as e: # pylint: disable=broad-except
+                MSG = 'Exception validating {:s}: {:s}'
+                self._logger.exception(MSG.format(str_subscription_name, str(resource_key)))
+                results.append(e) # if validation fails, store the exception
+                continue
+
+            subscription = 'subscribe', resource_key, sampling_duration, sampling_interval
+            self._in_subscriptions.put_nowait(subscription)
+            results.append(True)
+        return results
+
+    def unsubscribe(self, subscriptions : List[Tuple[str, float, float]]) -> List[Union[bool, Exception]]:
+        results = []
+        for i,subscription in enumerate(subscriptions):
+            str_subscription_name = 'subscriptions[#{:d}]'.format(i)
+            try:
+                chk_type(str_subscription_name, subscription, {list, tuple})
+                chk_length(str_subscription_name, subscription, min_length=3, max_length=3)
+                resource_key, sampling_duration, sampling_interval = subscription
+                chk_string(str_subscription_name + '.resource_key', resource_key, allow_empty=False)
+                chk_float(str_subscription_name + '.sampling_duration', sampling_duration, min_value=0)
+                chk_float(str_subscription_name + '.sampling_interval', sampling_interval, min_value=0)
+            except Exception as e: # pylint: disable=broad-except
+                MSG = 'Exception validating {:s}: {:s}'
+                self._logger.exception(MSG.format(str_subscription_name, str(resource_key)))
+                results.append(e) # if validation fails, store the exception
+                continue
+
+            subscription = 'unsubscribe', resource_key, sampling_duration, sampling_interval
+            self._in_subscriptions.put_nowait(subscription)
+            results.append(True)
+        return results
diff --git a/src/telemetry/backend/collectors/gnmi_openconfig/__init__.py b/src/telemetry/backend/collectors/gnmi_openconfig/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..023830645e0fcb60e3f8583674a954810af222f2
--- /dev/null
+++ b/src/telemetry/backend/collectors/gnmi_openconfig/__init__.py
@@ -0,0 +1,13 @@
+# Copyright 2022-2024 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/)
+#
+# 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.
diff --git a/src/telemetry/backend/collectors/gnmi_openconfig/clone-yang-models.sh b/src/telemetry/backend/collectors/gnmi_openconfig/clone-yang-models.sh
new file mode 100755
index 0000000000000000000000000000000000000000..eb97607847387beb2a1cb7cbe3f72fd29afed56e
--- /dev/null
+++ b/src/telemetry/backend/collectors/gnmi_openconfig/clone-yang-models.sh
@@ -0,0 +1,24 @@
+#!/bin/bash
+# Copyright 2022-2024 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/)
+#
+# 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.
+
+BASE_PATH=~/tfs-ctrl/src/telemetry/backend/collectors/gnmi_openconfig
+GIT_BASE_PATH=${BASE_PATH}/git/openconfig
+
+rm -rf ${GIT_BASE_PATH}
+
+OC_PUBLIC_PATH=${GIT_BASE_PATH}/public
+mkdir -p ${OC_PUBLIC_PATH}
+git clone https://github.com/openconfig/public.git ${OC_PUBLIC_PATH}
+
diff --git a/src/telemetry/backend/collectors/gnmi_openconfig/gnmi/Acknowledgement.txt b/src/telemetry/backend/collectors/gnmi_openconfig/gnmi/Acknowledgement.txt
new file mode 100644
index 0000000000000000000000000000000000000000..a004e1f58bdea3ba78263a06e6e473f593e1b390
--- /dev/null
+++ b/src/telemetry/backend/collectors/gnmi_openconfig/gnmi/Acknowledgement.txt
@@ -0,0 +1,25 @@
+This code is partially based on:
+https://github.com/nokia/pygnmi/blob/master/gNMI_Subscribe.py
+
+
+MIT License
+
+Copyright (c) 2017 Nokia
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
\ No newline at end of file
diff --git a/src/telemetry/backend/collectors/gnmi_openconfig/gnmi/__init__.py b/src/telemetry/backend/collectors/gnmi_openconfig/gnmi/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..53d5157f750bfb085125cbd33faff1cec5924e14
--- /dev/null
+++ b/src/telemetry/backend/collectors/gnmi_openconfig/gnmi/__init__.py
@@ -0,0 +1,14 @@
+# Copyright 2022-2024 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/)
+#
+# 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.
+
diff --git a/src/telemetry/backend/collectors/gnmi_openconfig/gnmi/gnmi.proto b/src/telemetry/backend/collectors/gnmi_openconfig/gnmi/gnmi.proto
new file mode 100644
index 0000000000000000000000000000000000000000..292880a55586f5a5c05b0edcfc0f2f73baf7be13
--- /dev/null
+++ b/src/telemetry/backend/collectors/gnmi_openconfig/gnmi/gnmi.proto
@@ -0,0 +1,501 @@
+syntax = "proto3";
+
+import "google/protobuf/any.proto";
+import "google/protobuf/descriptor.proto";
+// import gnmi_ext.proto;
+
+// Package gNMI defines a service specification for the gRPC Network Management
+// Interface. This interface is defined to be a standard interface via which
+// a network management system ("client") can subscribe to state values,
+// retrieve snapshots of state information, and manipulate the state of a data
+// tree supported by a device ("target").
+//
+// This document references the gNMI Specification which can be found at
+// http://github.com/openconfig/reference/blob/master/rpc/gnmi
+package gnmi;
+
+// Define a protobuf FileOption that defines the gNMI service version.
+extend google.protobuf.FileOptions {
+  // The gNMI service semantic version.
+  string gnmi_service = 1001;
+}
+
+// gNMI_service is the current version of the gNMI service, returned through
+// the Capabilities RPC.
+option (gnmi_service) = "0.8.0";
+
+option go_package = "github.com/openconfig/gnmi/proto/gnmi";
+option java_multiple_files = true;
+option java_outer_classname = "GnmiProto";
+option java_package = "com.github.gnmi.proto";
+
+
+service gNMI {
+  // Capabilities allows the client to retrieve the set of capabilities that
+  // is supported by the target. This allows the target to validate the
+  // service version that is implemented and retrieve the set of models that
+  // the target supports. The models can then be specified in subsequent RPCs
+  // to restrict the set of data that is utilized.
+  // Reference: gNMI Specification Section 3.2
+  rpc Capabilities(CapabilityRequest) returns (CapabilityResponse);
+  // Retrieve a snapshot of data from the target. A Get RPC requests that the
+  // target snapshots a subset of the data tree as specified by the paths
+  // included in the message and serializes this to be returned to the
+  // client using the specified encoding.
+  // Reference: gNMI Specification Section 3.3
+  rpc Get(GetRequest) returns (GetResponse);
+  // Set allows the client to modify the state of data on the target. The
+  // paths to modified along with the new values that the client wishes
+  // to set the value to.
+  // Reference: gNMI Specification Section 3.4
+  rpc Set(SetRequest) returns (SetResponse);
+  // Subscribe allows a client to request the target to send it values
+  // of particular paths within the data tree. These values may be streamed
+  // at a particular cadence (STREAM), sent one off on a long-lived channel
+  // (POLL), or sent as a one-off retrieval (ONCE).
+  // Reference: gNMI Specification Section 3.5
+  rpc Subscribe(stream SubscribeRequest) returns (stream SubscribeResponse);
+}
+// The Extension message contains a single gNMI extension.
+message Extension {
+  oneof ext {
+    RegisteredExtension registered_ext = 1;    // A registered extension.
+    // Well known extensions.
+    MasterArbitration master_arbitration = 2;  // Master arbitration extension.
+    History history = 3;                       // History extension.
+  }
+}
+
+// The RegisteredExtension message defines an extension which is defined outside
+// of this file.
+message RegisteredExtension {
+  ExtensionID id = 1; // The unique ID assigned to this extension.
+  bytes msg = 2;      // The binary-marshalled protobuf extension payload.
+}
+
+// RegisteredExtension is an enumeration acting as a registry for extensions
+// defined by external sources.
+enum ExtensionID {
+  EID_UNSET = 0;
+  // New extensions are to be defined within this enumeration - their definition
+  // MUST link to a reference describing their implementation.
+
+  // An experimental extension that may be used during prototyping of a new
+  // extension.
+  EID_EXPERIMENTAL = 999;
+}
+
+// MasterArbitration is used to select the master among multiple gNMI clients
+// with the same Roles. The client with the largest election_id is honored as
+// the master.
+// The document about gNMI master arbitration can be found at
+// https://github.com/openconfig/reference/blob/master/rpc/gnmi/gnmi-master-arbitration.md
+message MasterArbitration {
+  Role role = 1;
+  Uint128 election_id = 2;
+}
+
+// Representation of unsigned 128-bit integer.
+message Uint128 {
+  uint64 high = 1;
+  uint64 low = 2;
+}
+
+// There can be one master for each role. The role is identified by its id.
+message Role {
+  string id = 1;
+  // More fields can be added if needed, for example, to specify what paths the
+  // role can read/write.
+}
+
+// The History extension allows clients to request historical data. Its
+// spec can be found at
+// https://github.com/openconfig/reference/blob/master/rpc/gnmi/gnmi-history.md
+message History {
+  oneof request {
+    int64 snapshot_time = 1; // Nanoseconds since the epoch
+    TimeRange range = 2;
+  }
+}
+
+message TimeRange {
+  int64 start = 1; // Nanoseconds since the epoch
+  int64 end = 2;   // Nanoseconds since the epoch
+}
+// Notification is a re-usable message that is used to encode data from the
+// target to the client. A Notification carries two types of changes to the data
+// tree:
+//  - Deleted values (delete) - a set of paths that have been removed from the
+//    data tree.
+//  - Updated values (update) - a set of path-value pairs indicating the path
+//    whose value has changed in the data tree.
+// Reference: gNMI Specification Section 2.1
+message Notification {
+  int64 timestamp = 1;          // Timestamp in nanoseconds since Epoch.
+  Path prefix = 2;              // Prefix used for paths in the message.
+  repeated Update update = 4;   // Data elements that have changed values.
+  repeated Path delete = 5;     // Data elements that have been deleted.
+  // This notification contains a set of paths that are always updated together
+  // referenced by a globally unique prefix.
+  bool atomic = 6;
+  // Reserved field numbers and identifiers.
+  reserved "alias";
+  reserved 3;
+}
+
+// Update is a re-usable message that is used to store a particular Path,
+// Value pair.
+// Reference: gNMI Specification Section 2.1
+message Update {
+  Path path = 1;                      // The path (key) for the update.
+  Value value = 2 [deprecated=true];  // The value (value) for the update.
+  TypedValue val = 3;                 // The explicitly typed update value.
+  uint32 duplicates = 4;              // Number of coalesced duplicates.
+}
+
+// TypedValue is used to encode a value being sent between the client and
+// target (originated by either entity).
+message TypedValue {
+  // One of the fields within the val oneof is populated with the value
+  // of the update. The type of the value being included in the Update
+  // determines which field should be populated. In the case that the
+  // encoding is a particular form of the base protobuf type, a specific
+  // field is used to store the value (e.g., json_val).
+  oneof value {
+    string string_val = 1;            // String value.
+    int64 int_val = 2;                // Integer value.
+    uint64 uint_val = 3;              // Unsigned integer value.
+    bool bool_val = 4;                // Bool value.
+    bytes bytes_val = 5;              // Arbitrary byte sequence value.
+    float float_val = 6 [deprecated=true]; // Deprecated - use double_val.
+    double double_val = 14;           // Floating point value.
+    Decimal64 decimal_val = 7 [deprecated=true]; // Deprecated - use double_val.
+    ScalarArray leaflist_val = 8;     // Mixed type scalar array value.
+    google.protobuf.Any any_val = 9;  // protobuf.Any encoded bytes.
+    bytes json_val = 10;              // JSON-encoded text.
+    bytes json_ietf_val = 11;         // JSON-encoded text per RFC7951.
+    string ascii_val = 12;            // Arbitrary ASCII text.
+    // Protobuf binary encoded bytes. The message type is not included.
+    // See the specification at
+    // github.com/openconfig/reference/blob/master/rpc/gnmi/protobuf-vals.md
+    // for a complete specification. [Experimental]
+    bytes proto_bytes = 13;
+  }
+}
+
+// Path encodes a data tree path as a series of repeated strings, with
+// each element of the path representing a data tree node name and the
+// associated attributes.
+// Reference: gNMI Specification Section 2.2.2.
+message Path {
+  // Elements of the path are no longer encoded as a string, but rather within
+  // the elem field as a PathElem message.
+  repeated string element = 1 [deprecated=true];
+  string origin = 2;                              // Label to disambiguate path.
+  repeated PathElem elem = 3;                     // Elements of the path.
+  string target = 4;                              // The name of the target
+                                                  // (Sec. 2.2.2.1)
+}
+
+// PathElem encodes an element of a gNMI path, along with any attributes (keys)
+// that may be associated with it.
+// Reference: gNMI Specification Section 2.2.2.
+message PathElem {
+  string name = 1;                    // The name of the element in the path.
+  map<string, string> key = 2;        // Map of key (attribute) name to value.
+}
+
+// Value encodes a data tree node's value - along with the way in which
+// the value is encoded. This message is deprecated by gNMI 0.3.0.
+// Reference: gNMI Specification Section 2.2.3.
+message Value {
+  option deprecated = true;
+  bytes value = 1;      // Value of the variable being transmitted.
+  Encoding type = 2;    // Encoding used for the value field.
+}
+
+// Encoding defines the value encoding formats that are supported by the gNMI
+// protocol. These encodings are used by both the client (when sending Set
+// messages to modify the state of the target) and the target when serializing
+// data to be returned to the client (in both Subscribe and Get RPCs).
+// Reference: gNMI Specification Section 2.3
+enum Encoding {
+  JSON = 0;           // JSON encoded text.
+  BYTES = 1;          // Arbitrarily encoded bytes.
+  PROTO = 2;          // Encoded according to scalar values of TypedValue.
+  ASCII = 3;          // ASCII text of an out-of-band agreed format.
+  JSON_IETF = 4;      // JSON encoded text as per RFC7951.
+}
+
+// Error message previously utilised to return errors to the client. Deprecated
+// in favour of using the google.golang.org/genproto/googleapis/rpc/status
+// message in the RPC response.
+// Reference: gNMI Specification Section 2.5
+message Error {
+  option deprecated = true;
+  uint32 code = 1;                // Canonical gRPC error code.
+  string message = 2;             // Human readable error.
+  google.protobuf.Any data = 3;   // Optional additional information.
+}
+
+// Decimal64 is used to encode a fixed precision decimal number. The value
+// is expressed as a set of digits with the precision specifying the
+// number of digits following the decimal point in the digit set.
+// This message is deprecated in favor of encoding all floating point types
+// as double precision.
+message Decimal64 {
+  option deprecated = true;
+  int64 digits = 1;         // Set of digits.
+  uint32 precision = 2;     // Number of digits following the decimal point.
+}
+
+// ScalarArray is used to encode a mixed-type array of values.
+message ScalarArray {
+  // The set of elements within the array. Each TypedValue message should
+  // specify only elements that have a field identifier of 1-7 (i.e., the
+  // values are scalar values).
+  repeated TypedValue element = 1;
+}
+
+// SubscribeRequest is the message sent by the client to the target when
+// initiating a subscription to a set of paths within the data tree. The
+// request field must be populated and the initial message must specify a
+// SubscriptionList to initiate a subscription.
+// Reference: gNMI Specification Section 3.5.1.1
+message SubscribeRequest {
+  oneof request {
+    SubscriptionList subscribe = 1; // Specify the paths within a subscription.
+    Poll poll = 3;                  // Trigger a polled update.
+  }
+  // Extension messages associated with the SubscribeRequest. See the
+  // gNMI extension specification for further definition.
+  repeated Extension extension = 5;
+  // Reserved field numbers and identifiers.
+  reserved 4;
+  reserved "aliases";
+}
+
+// Poll is sent within a SubscribeRequest to trigger the device to
+// send telemetry updates for the paths that are associated with the
+// subscription.
+// Reference: gNMI Specification Section Section 3.5.1.4
+message Poll {
+}
+
+// SubscribeResponse is the message used by the target within a Subscribe RPC.
+// The target includes a Notification message which is used to transmit values
+// of the path(s) that are associated with the subscription. The same message
+// is to indicate that the target has sent all data values once (is
+// synchronized).
+// Reference: gNMI Specification Section 3.5.1.4
+message SubscribeResponse {
+  oneof response {
+    Notification update = 1;          // Changed or sampled value for a path.
+    // Indicate target has sent all values associated with the subscription
+    // at least once.
+    bool sync_response = 3;
+    // Deprecated in favour of google.golang.org/genproto/googleapis/rpc/status
+    Error error = 4 [deprecated=true];
+  }
+  // Extension messages associated with the SubscribeResponse. See the
+  // gNMI extension specification for further definition.
+  repeated Extension extension = 5;
+}
+
+// SubscriptionList is used within a Subscribe message to specify the list of
+// paths that the client wishes to subscribe to. The message consists of a
+// list of (possibly prefixed) paths, and options that relate to the
+// subscription.
+// Reference: gNMI Specification Section 3.5.1.2
+message SubscriptionList {
+  Path prefix = 1;                          // Prefix used for paths.
+  repeated Subscription subscription = 2;   // Set of subscriptions to create.
+  QOSMarking qos = 4;                       // DSCP marking to be used.
+  // Mode of the subscription.
+  enum Mode {
+    STREAM = 0; // Values streamed by the target (Sec. 3.5.1.5.2).
+    ONCE = 1;   // Values sent once-off by the target (Sec. 3.5.1.5.1).
+    POLL = 2;   // Values sent in response to a poll request (Sec. 3.5.1.5.3).
+  }
+  Mode mode = 5;
+  // Whether elements of the schema that are marked as eligible for aggregation
+  // should be aggregated or not.
+  bool allow_aggregation = 6;
+  // The set of schemas that define the elements of the data tree that should
+  // be sent by the target.
+  repeated ModelData use_models = 7;
+  // The encoding that the target should use within the Notifications generated
+  // corresponding to the SubscriptionList.
+  Encoding encoding = 8;
+  // An optional field to specify that only updates to current state should be
+  // sent to a client. If set, the initial state is not sent to the client but
+  // rather only the sync message followed by any subsequent updates to the
+  // current state. For ONCE and POLL modes, this causes the server to send only
+  // the sync message (Sec. 3.5.2.3).
+  bool updates_only = 9;
+  // Reserved field numbers and identifiers.
+  reserved 3;
+  reserved "use_aliases";
+}
+
+// Subscription is a single request within a SubscriptionList. The path
+// specified is interpreted (along with the prefix) as the elements of the data
+// tree that the client is subscribing to. The mode determines how the target
+// should trigger updates to be sent.
+// Reference: gNMI Specification Section 3.5.1.3
+message Subscription {
+  Path path = 1;                    // The data tree path.
+  SubscriptionMode mode = 2;        // Subscription mode to be used.
+  uint64 sample_interval = 3;       // ns between samples in SAMPLE mode.
+  // Indicates whether values that have not changed should be sent in a SAMPLE
+  // subscription.
+  bool suppress_redundant = 4;
+  // Specifies the maximum allowable silent period in nanoseconds when
+  // suppress_redundant is in use. The target should send a value at least once
+  // in the period specified.
+  uint64 heartbeat_interval = 5;
+}
+
+// SubscriptionMode is the mode of the subscription, specifying how the
+// target must return values in a subscription.
+// Reference: gNMI Specification Section 3.5.1.3
+enum SubscriptionMode {
+  TARGET_DEFINED = 0;  // The target selects the relevant mode for each element.
+  ON_CHANGE      = 1;  // The target sends an update on element value change.
+  SAMPLE         = 2;  // The target samples values according to the interval.
+}
+
+// QOSMarking specifies the DSCP value to be set on transmitted telemetry
+// updates from the target.
+// Reference: gNMI Specification Section 3.5.1.2
+message QOSMarking {
+  uint32 marking = 1;
+}
+
+// SetRequest is sent from a client to the target to update values in the data
+// tree. Paths are either deleted by the client, or modified by means of being
+// updated, or replaced. Where a replace is used, unspecified values are
+// considered to be replaced, whereas when update is used the changes are
+// considered to be incremental. The set of changes that are specified within
+// a single SetRequest are considered to be a transaction.
+// Reference: gNMI Specification Section 3.4.1
+message SetRequest {
+  Path prefix = 1;                // Prefix used for paths in the message.
+  repeated Path delete = 2;       // Paths to be deleted from the data tree.
+  repeated Update replace = 3;    // Updates specifying elements to be replaced.
+  repeated Update update = 4;     // Updates specifying elements to updated.
+  // Extension messages associated with the SetRequest. See the
+  // gNMI extension specification for further definition.
+  repeated Extension extension = 5;
+}
+
+// SetResponse is the response to a SetRequest, sent from the target to the
+// client. It reports the result of the modifications to the data tree that were
+// specified by the client. Errors for this RPC should be reported using the
+// https://github.com/googleapis/googleapis/blob/master/google/rpc/status.proto
+// message in the RPC return. The gnmi.Error message can be used to add additional
+// details where required.
+// Reference: gNMI Specification Section 3.4.2
+message SetResponse {
+  Path prefix = 1;                      // Prefix used for paths.
+  // A set of responses specifying the result of the operations specified in
+  // the SetRequest.
+  repeated UpdateResult response = 2;
+  Error message = 3 [deprecated=true]; // The overall status of the transaction.
+  int64 timestamp = 4;                 // Timestamp of transaction (ns since epoch).
+  // Extension messages associated with the SetResponse. See the
+  // gNMI extension specification for further definition.
+  repeated Extension extension = 5;
+}
+
+// UpdateResult is used within the SetResponse message to communicate the
+// result of an operation specified within a SetRequest message.
+// Reference: gNMI Specification Section 3.4.2
+message UpdateResult {
+  // The operation that was associated with the Path specified.
+  enum Operation {
+    INVALID = 0;
+    DELETE = 1;           // The result relates to a delete of Path.
+    REPLACE = 2;          // The result relates to a replace of Path.
+    UPDATE = 3;           // The result relates to an update of Path.
+  }
+  // Deprecated timestamp for the UpdateResult, this field has been
+  // replaced by the timestamp within the SetResponse message, since
+  // all mutations effected by a set should be applied as a single
+  // transaction.
+  int64 timestamp = 1 [deprecated=true];
+  Path path = 2;                            // Path associated with the update.
+  Error message = 3 [deprecated=true];      // Status of the update operation.
+  Operation op = 4;                         // Update operation type.
+}
+
+// GetRequest is sent when a client initiates a Get RPC. It is used to specify
+// the set of data elements for which the target should return a snapshot of
+// data. The use_models field specifies the set of schema modules that are to
+// be used by the target - where use_models is not specified then the target
+// must use all schema models that it has.
+// Reference: gNMI Specification Section 3.3.1
+message GetRequest {
+  Path prefix = 1;                      // Prefix used for paths.
+  repeated Path path = 2;               // Paths requested by the client.
+  // Type of elements within the data tree.
+  enum DataType {
+    ALL = 0;                            // All data elements.
+    CONFIG = 1;                         // Config (rw) only elements.
+    STATE = 2;                          // State (ro) only elements.
+    // Data elements marked in the schema as operational. This refers to data
+    // elements whose value relates to the state of processes or interactions
+    // running on the device.
+    OPERATIONAL = 3;
+  }
+  DataType type = 3;                    // The type of data being requested.
+  Encoding encoding = 5;                // Encoding to be used.
+  repeated ModelData use_models = 6;    // The schema models to be used.
+  // Extension messages associated with the GetRequest. See the
+  // gNMI extension specification for further definition.
+  repeated Extension extension = 7;
+}
+
+// GetResponse is used by the target to respond to a GetRequest from a client.
+// The set of Notifications corresponds to the data values that are requested
+// by the client in the GetRequest.
+// Reference: gNMI Specification Section 3.3.2
+message GetResponse {
+  repeated Notification notification = 1;   // Data values.
+  Error error = 2 [deprecated=true];        // Errors that occurred in the Get.
+  // Extension messages associated with the GetResponse. See the
+  // gNMI extension specification for further definition.
+  repeated Extension extension = 3;
+}
+
+// CapabilityRequest is sent by the client in the Capabilities RPC to request
+// that the target reports its capabilities.
+// Reference: gNMI Specification Section 3.2.1
+message CapabilityRequest {
+  // Extension messages associated with the CapabilityRequest. See the
+  // gNMI extension specification for further definition.
+  repeated Extension extension = 1;
+}
+
+// CapabilityResponse is used by the target to report its capabilities to the
+// client within the Capabilities RPC.
+// Reference: gNMI Specification Section 3.2.2
+message CapabilityResponse {
+  repeated ModelData supported_models = 1;    // Supported schema models.
+  repeated Encoding supported_encodings = 2;  // Supported encodings.
+  string gNMI_version = 3;                    // Supported gNMI version.
+  // Extension messages associated with the CapabilityResponse. See the
+  // gNMI extension specification for further definition.
+  repeated Extension extension = 4;
+}
+
+// ModelData is used to describe a set of schema modules. It can be used in a
+// CapabilityResponse where a target reports the set of modules that it
+// supports, and within the SubscribeRequest and GetRequest messages to specify
+// the set of models from which data tree elements should be reported.
+// Reference: gNMI Specification Section 3.2.3
+message ModelData {
+  string name = 1;            // Name of the model.
+  string organization = 2;    // Organization publishing the model.
+  string version = 3;         // Semantic version of the model.
+}
\ No newline at end of file
diff --git a/src/telemetry/backend/collectors/gnmi_openconfig/gnmi/gnmi_ext.proto b/src/telemetry/backend/collectors/gnmi_openconfig/gnmi/gnmi_ext.proto
new file mode 100644
index 0000000000000000000000000000000000000000..9960f12afa9d19a45b3d30fd127cb27586f02607
--- /dev/null
+++ b/src/telemetry/backend/collectors/gnmi_openconfig/gnmi/gnmi_ext.proto
@@ -0,0 +1,76 @@
+syntax = "proto3";
+
+// Package gnmi_ext defines a set of extensions messages which can be optionally
+// included with the request and response messages of gNMI RPCs. A set of
+// well-known extensions are defined within this file, along with a registry for
+// extensions defined outside of this package.
+package gnmi_ext;
+
+option go_package = "github.com/openconfig/gnmi/proto/gnmi_ext";
+
+// The Extension message contains a single gNMI extension.
+message Extension {
+  oneof ext {
+    RegisteredExtension registered_ext = 1;    // A registered extension.
+    // Well known extensions.
+    MasterArbitration master_arbitration = 2;  // Master arbitration extension.
+    History history = 3;                       // History extension.
+  }
+}
+
+// The RegisteredExtension message defines an extension which is defined outside
+// of this file.
+message RegisteredExtension {
+  ExtensionID id = 1; // The unique ID assigned to this extension.
+  bytes msg = 2;      // The binary-marshalled protobuf extension payload.
+}
+
+// RegisteredExtension is an enumeration acting as a registry for extensions
+// defined by external sources.
+enum ExtensionID {
+  EID_UNSET = 0;
+  // New extensions are to be defined within this enumeration - their definition
+  // MUST link to a reference describing their implementation.
+
+  // An experimental extension that may be used during prototyping of a new
+  // extension.
+  EID_EXPERIMENTAL = 999;
+}
+
+// MasterArbitration is used to select the master among multiple gNMI clients
+// with the same Roles. The client with the largest election_id is honored as
+// the master.
+// The document about gNMI master arbitration can be found at
+// https://github.com/openconfig/reference/blob/master/rpc/gnmi/gnmi-master-arbitration.md
+message MasterArbitration {
+  Role role = 1;
+  Uint128 election_id = 2;
+}
+
+// Representation of unsigned 128-bit integer.
+message Uint128 {
+  uint64 high = 1;
+  uint64 low = 2;
+}
+
+// There can be one master for each role. The role is identified by its id.
+message Role {
+  string id = 1;
+  // More fields can be added if needed, for example, to specify what paths the
+  // role can read/write.
+}
+
+// The History extension allows clients to request historical data. Its
+// spec can be found at
+// https://github.com/openconfig/reference/blob/master/rpc/gnmi/gnmi-history.md
+message History {
+  oneof request {
+    int64 snapshot_time = 1; // Nanoseconds since the epoch
+    TimeRange range = 2;
+  }
+}
+
+message TimeRange {
+  int64 start = 1; // Nanoseconds since the epoch
+  int64 end = 2;   // Nanoseconds since the epoch
+}
\ No newline at end of file
diff --git a/src/telemetry/backend/collectors/gnmi_openconfig/gnmi/gnmi_pb2.py b/src/telemetry/backend/collectors/gnmi_openconfig/gnmi/gnmi_pb2.py
new file mode 100644
index 0000000000000000000000000000000000000000..af67f9a8ca1d4e01d1a95a0d86adbabe6d8e83ea
--- /dev/null
+++ b/src/telemetry/backend/collectors/gnmi_openconfig/gnmi/gnmi_pb2.py
@@ -0,0 +1,129 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: gnmi.proto
+"""Generated protocol buffer code."""
+from google.protobuf.internal import builder as _builder
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import descriptor_pool as _descriptor_pool
+from google.protobuf import symbol_database as _symbol_database
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+from google.protobuf import any_pb2 as google_dot_protobuf_dot_any__pb2
+from google.protobuf import descriptor_pb2 as google_dot_protobuf_dot_descriptor__pb2
+
+
+DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\ngnmi.proto\x12\x04gnmi\x1a\x19google/protobuf/any.proto\x1a google/protobuf/descriptor.proto\"\xa0\x01\n\tExtension\x12\x33\n\x0eregistered_ext\x18\x01 \x01(\x0b\x32\x19.gnmi.RegisteredExtensionH\x00\x12\x35\n\x12master_arbitration\x18\x02 \x01(\x0b\x32\x17.gnmi.MasterArbitrationH\x00\x12 \n\x07history\x18\x03 \x01(\x0b\x32\r.gnmi.HistoryH\x00\x42\x05\n\x03\x65xt\"A\n\x13RegisteredExtension\x12\x1d\n\x02id\x18\x01 \x01(\x0e\x32\x11.gnmi.ExtensionID\x12\x0b\n\x03msg\x18\x02 \x01(\x0c\"Q\n\x11MasterArbitration\x12\x18\n\x04role\x18\x01 \x01(\x0b\x32\n.gnmi.Role\x12\"\n\x0b\x65lection_id\x18\x02 \x01(\x0b\x32\r.gnmi.Uint128\"$\n\x07Uint128\x12\x0c\n\x04high\x18\x01 \x01(\x04\x12\x0b\n\x03low\x18\x02 \x01(\x04\"\x12\n\x04Role\x12\n\n\x02id\x18\x01 \x01(\t\"O\n\x07History\x12\x17\n\rsnapshot_time\x18\x01 \x01(\x03H\x00\x12 \n\x05range\x18\x02 \x01(\x0b\x32\x0f.gnmi.TimeRangeH\x00\x42\t\n\x07request\"\'\n\tTimeRange\x12\r\n\x05start\x18\x01 \x01(\x03\x12\x0b\n\x03\x65nd\x18\x02 \x01(\x03\"\x94\x01\n\x0cNotification\x12\x11\n\ttimestamp\x18\x01 \x01(\x03\x12\x1a\n\x06prefix\x18\x02 \x01(\x0b\x32\n.gnmi.Path\x12\x1c\n\x06update\x18\x04 \x03(\x0b\x32\x0c.gnmi.Update\x12\x1a\n\x06\x64\x65lete\x18\x05 \x03(\x0b\x32\n.gnmi.Path\x12\x0e\n\x06\x61tomic\x18\x06 \x01(\x08J\x04\x08\x03\x10\x04R\x05\x61lias\"u\n\x06Update\x12\x18\n\x04path\x18\x01 \x01(\x0b\x32\n.gnmi.Path\x12\x1e\n\x05value\x18\x02 \x01(\x0b\x32\x0b.gnmi.ValueB\x02\x18\x01\x12\x1d\n\x03val\x18\x03 \x01(\x0b\x32\x10.gnmi.TypedValue\x12\x12\n\nduplicates\x18\x04 \x01(\r\"\x83\x03\n\nTypedValue\x12\x14\n\nstring_val\x18\x01 \x01(\tH\x00\x12\x11\n\x07int_val\x18\x02 \x01(\x03H\x00\x12\x12\n\x08uint_val\x18\x03 \x01(\x04H\x00\x12\x12\n\x08\x62ool_val\x18\x04 \x01(\x08H\x00\x12\x13\n\tbytes_val\x18\x05 \x01(\x0cH\x00\x12\x17\n\tfloat_val\x18\x06 \x01(\x02\x42\x02\x18\x01H\x00\x12\x14\n\ndouble_val\x18\x0e \x01(\x01H\x00\x12*\n\x0b\x64\x65\x63imal_val\x18\x07 \x01(\x0b\x32\x0f.gnmi.Decimal64B\x02\x18\x01H\x00\x12)\n\x0cleaflist_val\x18\x08 \x01(\x0b\x32\x11.gnmi.ScalarArrayH\x00\x12\'\n\x07\x61ny_val\x18\t \x01(\x0b\x32\x14.google.protobuf.AnyH\x00\x12\x12\n\x08json_val\x18\n \x01(\x0cH\x00\x12\x17\n\rjson_ietf_val\x18\x0b \x01(\x0cH\x00\x12\x13\n\tascii_val\x18\x0c \x01(\tH\x00\x12\x15\n\x0bproto_bytes\x18\r \x01(\x0cH\x00\x42\x07\n\x05value\"Y\n\x04Path\x12\x13\n\x07\x65lement\x18\x01 \x03(\tB\x02\x18\x01\x12\x0e\n\x06origin\x18\x02 \x01(\t\x12\x1c\n\x04\x65lem\x18\x03 \x03(\x0b\x32\x0e.gnmi.PathElem\x12\x0e\n\x06target\x18\x04 \x01(\t\"j\n\x08PathElem\x12\x0c\n\x04name\x18\x01 \x01(\t\x12$\n\x03key\x18\x02 \x03(\x0b\x32\x17.gnmi.PathElem.KeyEntry\x1a*\n\x08KeyEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"8\n\x05Value\x12\r\n\x05value\x18\x01 \x01(\x0c\x12\x1c\n\x04type\x18\x02 \x01(\x0e\x32\x0e.gnmi.Encoding:\x02\x18\x01\"N\n\x05\x45rror\x12\x0c\n\x04\x63ode\x18\x01 \x01(\r\x12\x0f\n\x07message\x18\x02 \x01(\t\x12\"\n\x04\x64\x61ta\x18\x03 \x01(\x0b\x32\x14.google.protobuf.Any:\x02\x18\x01\"2\n\tDecimal64\x12\x0e\n\x06\x64igits\x18\x01 \x01(\x03\x12\x11\n\tprecision\x18\x02 \x01(\r:\x02\x18\x01\"0\n\x0bScalarArray\x12!\n\x07\x65lement\x18\x01 \x03(\x0b\x32\x10.gnmi.TypedValue\"\x99\x01\n\x10SubscribeRequest\x12+\n\tsubscribe\x18\x01 \x01(\x0b\x32\x16.gnmi.SubscriptionListH\x00\x12\x1a\n\x04poll\x18\x03 \x01(\x0b\x32\n.gnmi.PollH\x00\x12\"\n\textension\x18\x05 \x03(\x0b\x32\x0f.gnmi.ExtensionB\t\n\x07requestJ\x04\x08\x04\x10\x05R\x07\x61liases\"\x06\n\x04Poll\"\xa4\x01\n\x11SubscribeResponse\x12$\n\x06update\x18\x01 \x01(\x0b\x32\x12.gnmi.NotificationH\x00\x12\x17\n\rsync_response\x18\x03 \x01(\x08H\x00\x12 \n\x05\x65rror\x18\x04 \x01(\x0b\x32\x0b.gnmi.ErrorB\x02\x18\x01H\x00\x12\"\n\textension\x18\x05 \x03(\x0b\x32\x0f.gnmi.ExtensionB\n\n\x08response\"\xd5\x02\n\x10SubscriptionList\x12\x1a\n\x06prefix\x18\x01 \x01(\x0b\x32\n.gnmi.Path\x12(\n\x0csubscription\x18\x02 \x03(\x0b\x32\x12.gnmi.Subscription\x12\x1d\n\x03qos\x18\x04 \x01(\x0b\x32\x10.gnmi.QOSMarking\x12)\n\x04mode\x18\x05 \x01(\x0e\x32\x1b.gnmi.SubscriptionList.Mode\x12\x19\n\x11\x61llow_aggregation\x18\x06 \x01(\x08\x12#\n\nuse_models\x18\x07 \x03(\x0b\x32\x0f.gnmi.ModelData\x12 \n\x08\x65ncoding\x18\x08 \x01(\x0e\x32\x0e.gnmi.Encoding\x12\x14\n\x0cupdates_only\x18\t \x01(\x08\"&\n\x04Mode\x12\n\n\x06STREAM\x10\x00\x12\x08\n\x04ONCE\x10\x01\x12\x08\n\x04POLL\x10\x02J\x04\x08\x03\x10\x04R\x0buse_aliases\"\x9f\x01\n\x0cSubscription\x12\x18\n\x04path\x18\x01 \x01(\x0b\x32\n.gnmi.Path\x12$\n\x04mode\x18\x02 \x01(\x0e\x32\x16.gnmi.SubscriptionMode\x12\x17\n\x0fsample_interval\x18\x03 \x01(\x04\x12\x1a\n\x12suppress_redundant\x18\x04 \x01(\x08\x12\x1a\n\x12heartbeat_interval\x18\x05 \x01(\x04\"\x1d\n\nQOSMarking\x12\x0f\n\x07marking\x18\x01 \x01(\r\"\xa5\x01\n\nSetRequest\x12\x1a\n\x06prefix\x18\x01 \x01(\x0b\x32\n.gnmi.Path\x12\x1a\n\x06\x64\x65lete\x18\x02 \x03(\x0b\x32\n.gnmi.Path\x12\x1d\n\x07replace\x18\x03 \x03(\x0b\x32\x0c.gnmi.Update\x12\x1c\n\x06update\x18\x04 \x03(\x0b\x32\x0c.gnmi.Update\x12\"\n\textension\x18\x05 \x03(\x0b\x32\x0f.gnmi.Extension\"\xa8\x01\n\x0bSetResponse\x12\x1a\n\x06prefix\x18\x01 \x01(\x0b\x32\n.gnmi.Path\x12$\n\x08response\x18\x02 \x03(\x0b\x32\x12.gnmi.UpdateResult\x12 \n\x07message\x18\x03 \x01(\x0b\x32\x0b.gnmi.ErrorB\x02\x18\x01\x12\x11\n\ttimestamp\x18\x04 \x01(\x03\x12\"\n\textension\x18\x05 \x03(\x0b\x32\x0f.gnmi.Extension\"\xca\x01\n\x0cUpdateResult\x12\x15\n\ttimestamp\x18\x01 \x01(\x03\x42\x02\x18\x01\x12\x18\n\x04path\x18\x02 \x01(\x0b\x32\n.gnmi.Path\x12 \n\x07message\x18\x03 \x01(\x0b\x32\x0b.gnmi.ErrorB\x02\x18\x01\x12(\n\x02op\x18\x04 \x01(\x0e\x32\x1c.gnmi.UpdateResult.Operation\"=\n\tOperation\x12\x0b\n\x07INVALID\x10\x00\x12\n\n\x06\x44\x45LETE\x10\x01\x12\x0b\n\x07REPLACE\x10\x02\x12\n\n\x06UPDATE\x10\x03\"\x93\x02\n\nGetRequest\x12\x1a\n\x06prefix\x18\x01 \x01(\x0b\x32\n.gnmi.Path\x12\x18\n\x04path\x18\x02 \x03(\x0b\x32\n.gnmi.Path\x12\'\n\x04type\x18\x03 \x01(\x0e\x32\x19.gnmi.GetRequest.DataType\x12 \n\x08\x65ncoding\x18\x05 \x01(\x0e\x32\x0e.gnmi.Encoding\x12#\n\nuse_models\x18\x06 \x03(\x0b\x32\x0f.gnmi.ModelData\x12\"\n\textension\x18\x07 \x03(\x0b\x32\x0f.gnmi.Extension\";\n\x08\x44\x61taType\x12\x07\n\x03\x41LL\x10\x00\x12\n\n\x06\x43ONFIG\x10\x01\x12\t\n\x05STATE\x10\x02\x12\x0f\n\x0bOPERATIONAL\x10\x03\"{\n\x0bGetResponse\x12(\n\x0cnotification\x18\x01 \x03(\x0b\x32\x12.gnmi.Notification\x12\x1e\n\x05\x65rror\x18\x02 \x01(\x0b\x32\x0b.gnmi.ErrorB\x02\x18\x01\x12\"\n\textension\x18\x03 \x03(\x0b\x32\x0f.gnmi.Extension\"7\n\x11\x43\x61pabilityRequest\x12\"\n\textension\x18\x01 \x03(\x0b\x32\x0f.gnmi.Extension\"\xa6\x01\n\x12\x43\x61pabilityResponse\x12)\n\x10supported_models\x18\x01 \x03(\x0b\x32\x0f.gnmi.ModelData\x12+\n\x13supported_encodings\x18\x02 \x03(\x0e\x32\x0e.gnmi.Encoding\x12\x14\n\x0cgNMI_version\x18\x03 \x01(\t\x12\"\n\textension\x18\x04 \x03(\x0b\x32\x0f.gnmi.Extension\"@\n\tModelData\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x14\n\x0corganization\x18\x02 \x01(\t\x12\x0f\n\x07version\x18\x03 \x01(\t*3\n\x0b\x45xtensionID\x12\r\n\tEID_UNSET\x10\x00\x12\x15\n\x10\x45ID_EXPERIMENTAL\x10\xe7\x07*D\n\x08\x45ncoding\x12\x08\n\x04JSON\x10\x00\x12\t\n\x05\x42YTES\x10\x01\x12\t\n\x05PROTO\x10\x02\x12\t\n\x05\x41SCII\x10\x03\x12\r\n\tJSON_IETF\x10\x04*A\n\x10SubscriptionMode\x12\x12\n\x0eTARGET_DEFINED\x10\x00\x12\r\n\tON_CHANGE\x10\x01\x12\n\n\x06SAMPLE\x10\x02\x32\xe3\x01\n\x04gNMI\x12\x41\n\x0c\x43\x61pabilities\x12\x17.gnmi.CapabilityRequest\x1a\x18.gnmi.CapabilityResponse\x12*\n\x03Get\x12\x10.gnmi.GetRequest\x1a\x11.gnmi.GetResponse\x12*\n\x03Set\x12\x10.gnmi.SetRequest\x1a\x11.gnmi.SetResponse\x12@\n\tSubscribe\x12\x16.gnmi.SubscribeRequest\x1a\x17.gnmi.SubscribeResponse(\x01\x30\x01:3\n\x0cgnmi_service\x12\x1c.google.protobuf.FileOptions\x18\xe9\x07 \x01(\tBS\n\x15\x63om.github.gnmi.protoB\tGnmiProtoP\x01Z%github.com/openconfig/gnmi/proto/gnmi\xca>\x05\x30.8.0b\x06proto3')
+
+_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
+_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'gnmi_pb2', globals())
+if _descriptor._USE_C_DESCRIPTORS == False:
+  google_dot_protobuf_dot_descriptor__pb2.FileOptions.RegisterExtension(gnmi_service)
+
+  DESCRIPTOR._options = None
+  DESCRIPTOR._serialized_options = b'\n\025com.github.gnmi.protoB\tGnmiProtoP\001Z%github.com/openconfig/gnmi/proto/gnmi\312>\0050.8.0'
+  _UPDATE.fields_by_name['value']._options = None
+  _UPDATE.fields_by_name['value']._serialized_options = b'\030\001'
+  _TYPEDVALUE.fields_by_name['float_val']._options = None
+  _TYPEDVALUE.fields_by_name['float_val']._serialized_options = b'\030\001'
+  _TYPEDVALUE.fields_by_name['decimal_val']._options = None
+  _TYPEDVALUE.fields_by_name['decimal_val']._serialized_options = b'\030\001'
+  _PATH.fields_by_name['element']._options = None
+  _PATH.fields_by_name['element']._serialized_options = b'\030\001'
+  _PATHELEM_KEYENTRY._options = None
+  _PATHELEM_KEYENTRY._serialized_options = b'8\001'
+  _VALUE._options = None
+  _VALUE._serialized_options = b'\030\001'
+  _ERROR._options = None
+  _ERROR._serialized_options = b'\030\001'
+  _DECIMAL64._options = None
+  _DECIMAL64._serialized_options = b'\030\001'
+  _SUBSCRIBERESPONSE.fields_by_name['error']._options = None
+  _SUBSCRIBERESPONSE.fields_by_name['error']._serialized_options = b'\030\001'
+  _SETRESPONSE.fields_by_name['message']._options = None
+  _SETRESPONSE.fields_by_name['message']._serialized_options = b'\030\001'
+  _UPDATERESULT.fields_by_name['timestamp']._options = None
+  _UPDATERESULT.fields_by_name['timestamp']._serialized_options = b'\030\001'
+  _UPDATERESULT.fields_by_name['message']._options = None
+  _UPDATERESULT.fields_by_name['message']._serialized_options = b'\030\001'
+  _GETRESPONSE.fields_by_name['error']._options = None
+  _GETRESPONSE.fields_by_name['error']._serialized_options = b'\030\001'
+  _EXTENSIONID._serialized_start=3780
+  _EXTENSIONID._serialized_end=3831
+  _ENCODING._serialized_start=3833
+  _ENCODING._serialized_end=3901
+  _SUBSCRIPTIONMODE._serialized_start=3903
+  _SUBSCRIPTIONMODE._serialized_end=3968
+  _EXTENSION._serialized_start=82
+  _EXTENSION._serialized_end=242
+  _REGISTEREDEXTENSION._serialized_start=244
+  _REGISTEREDEXTENSION._serialized_end=309
+  _MASTERARBITRATION._serialized_start=311
+  _MASTERARBITRATION._serialized_end=392
+  _UINT128._serialized_start=394
+  _UINT128._serialized_end=430
+  _ROLE._serialized_start=432
+  _ROLE._serialized_end=450
+  _HISTORY._serialized_start=452
+  _HISTORY._serialized_end=531
+  _TIMERANGE._serialized_start=533
+  _TIMERANGE._serialized_end=572
+  _NOTIFICATION._serialized_start=575
+  _NOTIFICATION._serialized_end=723
+  _UPDATE._serialized_start=725
+  _UPDATE._serialized_end=842
+  _TYPEDVALUE._serialized_start=845
+  _TYPEDVALUE._serialized_end=1232
+  _PATH._serialized_start=1234
+  _PATH._serialized_end=1323
+  _PATHELEM._serialized_start=1325
+  _PATHELEM._serialized_end=1431
+  _PATHELEM_KEYENTRY._serialized_start=1389
+  _PATHELEM_KEYENTRY._serialized_end=1431
+  _VALUE._serialized_start=1433
+  _VALUE._serialized_end=1489
+  _ERROR._serialized_start=1491
+  _ERROR._serialized_end=1569
+  _DECIMAL64._serialized_start=1571
+  _DECIMAL64._serialized_end=1621
+  _SCALARARRAY._serialized_start=1623
+  _SCALARARRAY._serialized_end=1671
+  _SUBSCRIBEREQUEST._serialized_start=1674
+  _SUBSCRIBEREQUEST._serialized_end=1827
+  _POLL._serialized_start=1829
+  _POLL._serialized_end=1835
+  _SUBSCRIBERESPONSE._serialized_start=1838
+  _SUBSCRIBERESPONSE._serialized_end=2002
+  _SUBSCRIPTIONLIST._serialized_start=2005
+  _SUBSCRIPTIONLIST._serialized_end=2346
+  _SUBSCRIPTIONLIST_MODE._serialized_start=2289
+  _SUBSCRIPTIONLIST_MODE._serialized_end=2327
+  _SUBSCRIPTION._serialized_start=2349
+  _SUBSCRIPTION._serialized_end=2508
+  _QOSMARKING._serialized_start=2510
+  _QOSMARKING._serialized_end=2539
+  _SETREQUEST._serialized_start=2542
+  _SETREQUEST._serialized_end=2707
+  _SETRESPONSE._serialized_start=2710
+  _SETRESPONSE._serialized_end=2878
+  _UPDATERESULT._serialized_start=2881
+  _UPDATERESULT._serialized_end=3083
+  _UPDATERESULT_OPERATION._serialized_start=3022
+  _UPDATERESULT_OPERATION._serialized_end=3083
+  _GETREQUEST._serialized_start=3086
+  _GETREQUEST._serialized_end=3361
+  _GETREQUEST_DATATYPE._serialized_start=3302
+  _GETREQUEST_DATATYPE._serialized_end=3361
+  _GETRESPONSE._serialized_start=3363
+  _GETRESPONSE._serialized_end=3486
+  _CAPABILITYREQUEST._serialized_start=3488
+  _CAPABILITYREQUEST._serialized_end=3543
+  _CAPABILITYRESPONSE._serialized_start=3546
+  _CAPABILITYRESPONSE._serialized_end=3712
+  _MODELDATA._serialized_start=3714
+  _MODELDATA._serialized_end=3778
+  _GNMI._serialized_start=3971
+  _GNMI._serialized_end=4198
+# @@protoc_insertion_point(module_scope)
diff --git a/src/telemetry/backend/collectors/gnmi_openconfig/gnmi/gnmi_pb2.py.old b/src/telemetry/backend/collectors/gnmi_openconfig/gnmi/gnmi_pb2.py.old
new file mode 100644
index 0000000000000000000000000000000000000000..313674f8ce5be1586c63df02226570f5082544ba
--- /dev/null
+++ b/src/telemetry/backend/collectors/gnmi_openconfig/gnmi/gnmi_pb2.py.old
@@ -0,0 +1,2037 @@
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: proto/gnmi/gnmi.proto
+
+import sys
+_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))
+from google.protobuf.internal import enum_type_wrapper
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import message as _message
+from google.protobuf import reflection as _reflection
+from google.protobuf import symbol_database as _symbol_database
+from google.protobuf import descriptor_pb2
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+from google.protobuf import any_pb2 as google_dot_protobuf_dot_any__pb2
+from google.protobuf import descriptor_pb2 as google_dot_protobuf_dot_descriptor__pb2
+
+
+DESCRIPTOR = _descriptor.FileDescriptor(
+  name='proto/gnmi/gnmi.proto',
+  package='gnmi',
+  syntax='proto3',
+  serialized_pb=_b('\n\x15proto/gnmi/gnmi.proto\x12\x04gnmi\x1a\x19google/protobuf/any.proto\x1a google/protobuf/descriptor.proto\"\x86\x01\n\x0cNotification\x12\x11\n\ttimestamp\x18\x01 \x01(\x03\x12\x1a\n\x06prefix\x18\x02 \x01(\x0b\x32\n.gnmi.Path\x12\r\n\x05\x61lias\x18\x03 \x01(\t\x12\x1c\n\x06update\x18\x04 \x03(\x0b\x32\x0c.gnmi.Update\x12\x1a\n\x06\x64\x65lete\x18\x05 \x03(\x0b\x32\n.gnmi.Path\"u\n\x06Update\x12\x18\n\x04path\x18\x01 \x01(\x0b\x32\n.gnmi.Path\x12\x1e\n\x05value\x18\x02 \x01(\x0b\x32\x0b.gnmi.ValueB\x02\x18\x01\x12\x1d\n\x03val\x18\x03 \x01(\x0b\x32\x10.gnmi.TypedValue\x12\x12\n\nduplicates\x18\x04 \x01(\r\"\xce\x02\n\nTypedValue\x12\x14\n\nstring_val\x18\x01 \x01(\tH\x00\x12\x11\n\x07int_val\x18\x02 \x01(\x03H\x00\x12\x12\n\x08uint_val\x18\x03 \x01(\x04H\x00\x12\x12\n\x08\x62ool_val\x18\x04 \x01(\x08H\x00\x12\x13\n\tbytes_val\x18\x05 \x01(\x0cH\x00\x12\x13\n\tfloat_val\x18\x06 \x01(\x02H\x00\x12&\n\x0b\x64\x65\x63imal_val\x18\x07 \x01(\x0b\x32\x0f.gnmi.Decimal64H\x00\x12)\n\x0cleaflist_val\x18\x08 \x01(\x0b\x32\x11.gnmi.ScalarArrayH\x00\x12\'\n\x07\x61ny_val\x18\t \x01(\x0b\x32\x14.google.protobuf.AnyH\x00\x12\x12\n\x08json_val\x18\n \x01(\x0cH\x00\x12\x17\n\rjson_ietf_val\x18\x0b \x01(\x0cH\x00\x12\x13\n\tascii_val\x18\x0c \x01(\tH\x00\x42\x07\n\x05value\"Y\n\x04Path\x12\x13\n\x07\x65lement\x18\x01 \x03(\tB\x02\x18\x01\x12\x0e\n\x06origin\x18\x02 \x01(\t\x12\x1c\n\x04\x65lem\x18\x03 \x03(\x0b\x32\x0e.gnmi.PathElem\x12\x0e\n\x06target\x18\x04 \x01(\t\"j\n\x08PathElem\x12\x0c\n\x04name\x18\x01 \x01(\t\x12$\n\x03key\x18\x02 \x03(\x0b\x32\x17.gnmi.PathElem.KeyEntry\x1a*\n\x08KeyEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"8\n\x05Value\x12\r\n\x05value\x18\x01 \x01(\x0c\x12\x1c\n\x04type\x18\x02 \x01(\x0e\x32\x0e.gnmi.Encoding:\x02\x18\x01\"N\n\x05\x45rror\x12\x0c\n\x04\x63ode\x18\x01 \x01(\r\x12\x0f\n\x07message\x18\x02 \x01(\t\x12\"\n\x04\x64\x61ta\x18\x03 \x01(\x0b\x32\x14.google.protobuf.Any:\x02\x18\x01\".\n\tDecimal64\x12\x0e\n\x06\x64igits\x18\x01 \x01(\x04\x12\x11\n\tprecision\x18\x02 \x01(\r\"0\n\x0bScalarArray\x12!\n\x07\x65lement\x18\x01 \x03(\x0b\x32\x10.gnmi.TypedValue\"\x8a\x01\n\x10SubscribeRequest\x12+\n\tsubscribe\x18\x01 \x01(\x0b\x32\x16.gnmi.SubscriptionListH\x00\x12\x1a\n\x04poll\x18\x03 \x01(\x0b\x32\n.gnmi.PollH\x00\x12\"\n\x07\x61liases\x18\x04 \x01(\x0b\x32\x0f.gnmi.AliasListH\x00\x42\t\n\x07request\"\x06\n\x04Poll\"\x80\x01\n\x11SubscribeResponse\x12$\n\x06update\x18\x01 \x01(\x0b\x32\x12.gnmi.NotificationH\x00\x12\x17\n\rsync_response\x18\x03 \x01(\x08H\x00\x12 \n\x05\x65rror\x18\x04 \x01(\x0b\x32\x0b.gnmi.ErrorB\x02\x18\x01H\x00\x42\n\n\x08response\"\xd7\x02\n\x10SubscriptionList\x12\x1a\n\x06prefix\x18\x01 \x01(\x0b\x32\n.gnmi.Path\x12(\n\x0csubscription\x18\x02 \x03(\x0b\x32\x12.gnmi.Subscription\x12\x13\n\x0buse_aliases\x18\x03 \x01(\x08\x12\x1d\n\x03qos\x18\x04 \x01(\x0b\x32\x10.gnmi.QOSMarking\x12)\n\x04mode\x18\x05 \x01(\x0e\x32\x1b.gnmi.SubscriptionList.Mode\x12\x19\n\x11\x61llow_aggregation\x18\x06 \x01(\x08\x12#\n\nuse_models\x18\x07 \x03(\x0b\x32\x0f.gnmi.ModelData\x12 \n\x08\x65ncoding\x18\x08 \x01(\x0e\x32\x0e.gnmi.Encoding\x12\x14\n\x0cupdates_only\x18\t \x01(\x08\"&\n\x04Mode\x12\n\n\x06STREAM\x10\x00\x12\x08\n\x04ONCE\x10\x01\x12\x08\n\x04POLL\x10\x02\"\x9f\x01\n\x0cSubscription\x12\x18\n\x04path\x18\x01 \x01(\x0b\x32\n.gnmi.Path\x12$\n\x04mode\x18\x02 \x01(\x0e\x32\x16.gnmi.SubscriptionMode\x12\x17\n\x0fsample_interval\x18\x03 \x01(\x04\x12\x1a\n\x12suppress_redundant\x18\x04 \x01(\x08\x12\x1a\n\x12heartbeat_interval\x18\x05 \x01(\x04\"\x1d\n\nQOSMarking\x12\x0f\n\x07marking\x18\x01 \x01(\r\"0\n\x05\x41lias\x12\x18\n\x04path\x18\x01 \x01(\x0b\x32\n.gnmi.Path\x12\r\n\x05\x61lias\x18\x02 \x01(\t\"\'\n\tAliasList\x12\x1a\n\x05\x61lias\x18\x01 \x03(\x0b\x32\x0b.gnmi.Alias\"\x81\x01\n\nSetRequest\x12\x1a\n\x06prefix\x18\x01 \x01(\x0b\x32\n.gnmi.Path\x12\x1a\n\x06\x64\x65lete\x18\x02 \x03(\x0b\x32\n.gnmi.Path\x12\x1d\n\x07replace\x18\x03 \x03(\x0b\x32\x0c.gnmi.Update\x12\x1c\n\x06update\x18\x04 \x03(\x0b\x32\x0c.gnmi.Update\"\x84\x01\n\x0bSetResponse\x12\x1a\n\x06prefix\x18\x01 \x01(\x0b\x32\n.gnmi.Path\x12$\n\x08response\x18\x02 \x03(\x0b\x32\x12.gnmi.UpdateResult\x12 \n\x07message\x18\x03 \x01(\x0b\x32\x0b.gnmi.ErrorB\x02\x18\x01\x12\x11\n\ttimestamp\x18\x04 \x01(\x03\"\xca\x01\n\x0cUpdateResult\x12\x15\n\ttimestamp\x18\x01 \x01(\x03\x42\x02\x18\x01\x12\x18\n\x04path\x18\x02 \x01(\x0b\x32\n.gnmi.Path\x12 \n\x07message\x18\x03 \x01(\x0b\x32\x0b.gnmi.ErrorB\x02\x18\x01\x12(\n\x02op\x18\x04 \x01(\x0e\x32\x1c.gnmi.UpdateResult.Operation\"=\n\tOperation\x12\x0b\n\x07INVALID\x10\x00\x12\n\n\x06\x44\x45LETE\x10\x01\x12\x0b\n\x07REPLACE\x10\x02\x12\n\n\x06UPDATE\x10\x03\"\xef\x01\n\nGetRequest\x12\x1a\n\x06prefix\x18\x01 \x01(\x0b\x32\n.gnmi.Path\x12\x18\n\x04path\x18\x02 \x03(\x0b\x32\n.gnmi.Path\x12\'\n\x04type\x18\x03 \x01(\x0e\x32\x19.gnmi.GetRequest.DataType\x12 \n\x08\x65ncoding\x18\x05 \x01(\x0e\x32\x0e.gnmi.Encoding\x12#\n\nuse_models\x18\x06 \x03(\x0b\x32\x0f.gnmi.ModelData\";\n\x08\x44\x61taType\x12\x07\n\x03\x41LL\x10\x00\x12\n\n\x06\x43ONFIG\x10\x01\x12\t\n\x05STATE\x10\x02\x12\x0f\n\x0bOPERATIONAL\x10\x03\"W\n\x0bGetResponse\x12(\n\x0cnotification\x18\x01 \x03(\x0b\x32\x12.gnmi.Notification\x12\x1e\n\x05\x65rror\x18\x02 \x01(\x0b\x32\x0b.gnmi.ErrorB\x02\x18\x01\"\x13\n\x11\x43\x61pabilityRequest\"\x82\x01\n\x12\x43\x61pabilityResponse\x12)\n\x10supported_models\x18\x01 \x03(\x0b\x32\x0f.gnmi.ModelData\x12+\n\x13supported_encodings\x18\x02 \x03(\x0e\x32\x0e.gnmi.Encoding\x12\x14\n\x0cgNMI_version\x18\x03 \x01(\t\"@\n\tModelData\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x14\n\x0corganization\x18\x02 \x01(\t\x12\x0f\n\x07version\x18\x03 \x01(\t*D\n\x08\x45ncoding\x12\x08\n\x04JSON\x10\x00\x12\t\n\x05\x42YTES\x10\x01\x12\t\n\x05PROTO\x10\x02\x12\t\n\x05\x41SCII\x10\x03\x12\r\n\tJSON_IETF\x10\x04*A\n\x10SubscriptionMode\x12\x12\n\x0eTARGET_DEFINED\x10\x00\x12\r\n\tON_CHANGE\x10\x01\x12\n\n\x06SAMPLE\x10\x02\x32\xe3\x01\n\x04gNMI\x12\x41\n\x0c\x43\x61pabilities\x12\x17.gnmi.CapabilityRequest\x1a\x18.gnmi.CapabilityResponse\x12*\n\x03Get\x12\x10.gnmi.GetRequest\x1a\x11.gnmi.GetResponse\x12*\n\x03Set\x12\x10.gnmi.SetRequest\x1a\x11.gnmi.SetResponse\x12@\n\tSubscribe\x12\x16.gnmi.SubscribeRequest\x1a\x17.gnmi.SubscribeResponse(\x01\x30\x01:3\n\x0cgnmi_service\x12\x1c.google.protobuf.FileOptions\x18\xe9\x07 \x01(\tB\x08\xca>\x05\x30.5.0b\x06proto3')
+  ,
+  dependencies=[google_dot_protobuf_dot_any__pb2.DESCRIPTOR,google_dot_protobuf_dot_descriptor__pb2.DESCRIPTOR,])
+
+_ENCODING = _descriptor.EnumDescriptor(
+  name='Encoding',
+  full_name='gnmi.Encoding',
+  filename=None,
+  file=DESCRIPTOR,
+  values=[
+    _descriptor.EnumValueDescriptor(
+      name='JSON', index=0, number=0,
+      options=None,
+      type=None),
+    _descriptor.EnumValueDescriptor(
+      name='BYTES', index=1, number=1,
+      options=None,
+      type=None),
+    _descriptor.EnumValueDescriptor(
+      name='PROTO', index=2, number=2,
+      options=None,
+      type=None),
+    _descriptor.EnumValueDescriptor(
+      name='ASCII', index=3, number=3,
+      options=None,
+      type=None),
+    _descriptor.EnumValueDescriptor(
+      name='JSON_IETF', index=4, number=4,
+      options=None,
+      type=None),
+  ],
+  containing_type=None,
+  options=None,
+  serialized_start=3053,
+  serialized_end=3121,
+)
+_sym_db.RegisterEnumDescriptor(_ENCODING)
+
+Encoding = enum_type_wrapper.EnumTypeWrapper(_ENCODING)
+_SUBSCRIPTIONMODE = _descriptor.EnumDescriptor(
+  name='SubscriptionMode',
+  full_name='gnmi.SubscriptionMode',
+  filename=None,
+  file=DESCRIPTOR,
+  values=[
+    _descriptor.EnumValueDescriptor(
+      name='TARGET_DEFINED', index=0, number=0,
+      options=None,
+      type=None),
+    _descriptor.EnumValueDescriptor(
+      name='ON_CHANGE', index=1, number=1,
+      options=None,
+      type=None),
+    _descriptor.EnumValueDescriptor(
+      name='SAMPLE', index=2, number=2,
+      options=None,
+      type=None),
+  ],
+  containing_type=None,
+  options=None,
+  serialized_start=3123,
+  serialized_end=3188,
+)
+_sym_db.RegisterEnumDescriptor(_SUBSCRIPTIONMODE)
+
+SubscriptionMode = enum_type_wrapper.EnumTypeWrapper(_SUBSCRIPTIONMODE)
+JSON = 0
+BYTES = 1
+PROTO = 2
+ASCII = 3
+JSON_IETF = 4
+TARGET_DEFINED = 0
+ON_CHANGE = 1
+SAMPLE = 2
+
+GNMI_SERVICE_FIELD_NUMBER = 1001
+gnmi_service = _descriptor.FieldDescriptor(
+  name='gnmi_service', full_name='gnmi.gnmi_service', index=0,
+  number=1001, type=9, cpp_type=9, label=1,
+  has_default_value=False, default_value=_b("").decode('utf-8'),
+  message_type=None, enum_type=None, containing_type=None,
+  is_extension=True, extension_scope=None,
+  options=None)
+
+_SUBSCRIPTIONLIST_MODE = _descriptor.EnumDescriptor(
+  name='Mode',
+  full_name='gnmi.SubscriptionList.Mode',
+  filename=None,
+  file=DESCRIPTOR,
+  values=[
+    _descriptor.EnumValueDescriptor(
+      name='STREAM', index=0, number=0,
+      options=None,
+      type=None),
+    _descriptor.EnumValueDescriptor(
+      name='ONCE', index=1, number=1,
+      options=None,
+      type=None),
+    _descriptor.EnumValueDescriptor(
+      name='POLL', index=2, number=2,
+      options=None,
+      type=None),
+  ],
+  containing_type=None,
+  options=None,
+  serialized_start=1706,
+  serialized_end=1744,
+)
+_sym_db.RegisterEnumDescriptor(_SUBSCRIPTIONLIST_MODE)
+
+_UPDATERESULT_OPERATION = _descriptor.EnumDescriptor(
+  name='Operation',
+  full_name='gnmi.UpdateResult.Operation',
+  filename=None,
+  file=DESCRIPTOR,
+  values=[
+    _descriptor.EnumValueDescriptor(
+      name='INVALID', index=0, number=0,
+      options=None,
+      type=None),
+    _descriptor.EnumValueDescriptor(
+      name='DELETE', index=1, number=1,
+      options=None,
+      type=None),
+    _descriptor.EnumValueDescriptor(
+      name='REPLACE', index=2, number=2,
+      options=None,
+      type=None),
+    _descriptor.EnumValueDescriptor(
+      name='UPDATE', index=3, number=3,
+      options=None,
+      type=None),
+  ],
+  containing_type=None,
+  options=None,
+  serialized_start=2439,
+  serialized_end=2500,
+)
+_sym_db.RegisterEnumDescriptor(_UPDATERESULT_OPERATION)
+
+_GETREQUEST_DATATYPE = _descriptor.EnumDescriptor(
+  name='DataType',
+  full_name='gnmi.GetRequest.DataType',
+  filename=None,
+  file=DESCRIPTOR,
+  values=[
+    _descriptor.EnumValueDescriptor(
+      name='ALL', index=0, number=0,
+      options=None,
+      type=None),
+    _descriptor.EnumValueDescriptor(
+      name='CONFIG', index=1, number=1,
+      options=None,
+      type=None),
+    _descriptor.EnumValueDescriptor(
+      name='STATE', index=2, number=2,
+      options=None,
+      type=None),
+    _descriptor.EnumValueDescriptor(
+      name='OPERATIONAL', index=3, number=3,
+      options=None,
+      type=None),
+  ],
+  containing_type=None,
+  options=None,
+  serialized_start=2683,
+  serialized_end=2742,
+)
+_sym_db.RegisterEnumDescriptor(_GETREQUEST_DATATYPE)
+
+
+_NOTIFICATION = _descriptor.Descriptor(
+  name='Notification',
+  full_name='gnmi.Notification',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='timestamp', full_name='gnmi.Notification.timestamp', index=0,
+      number=1, type=3, cpp_type=2, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    _descriptor.FieldDescriptor(
+      name='prefix', full_name='gnmi.Notification.prefix', index=1,
+      number=2, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    _descriptor.FieldDescriptor(
+      name='alias', full_name='gnmi.Notification.alias', index=2,
+      number=3, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=_b("").decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    _descriptor.FieldDescriptor(
+      name='update', full_name='gnmi.Notification.update', index=3,
+      number=4, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    _descriptor.FieldDescriptor(
+      name='delete', full_name='gnmi.Notification.delete', index=4,
+      number=5, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=93,
+  serialized_end=227,
+)
+
+
+_UPDATE = _descriptor.Descriptor(
+  name='Update',
+  full_name='gnmi.Update',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='path', full_name='gnmi.Update.path', index=0,
+      number=1, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    _descriptor.FieldDescriptor(
+      name='value', full_name='gnmi.Update.value', index=1,
+      number=2, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=_descriptor._ParseOptions(descriptor_pb2.FieldOptions(), _b('\030\001'))),
+    _descriptor.FieldDescriptor(
+      name='val', full_name='gnmi.Update.val', index=2,
+      number=3, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    _descriptor.FieldDescriptor(
+      name='duplicates', full_name='gnmi.Update.duplicates', index=3,
+      number=4, type=13, cpp_type=3, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=229,
+  serialized_end=346,
+)
+
+
+_TYPEDVALUE = _descriptor.Descriptor(
+  name='TypedValue',
+  full_name='gnmi.TypedValue',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='string_val', full_name='gnmi.TypedValue.string_val', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=_b("").decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    _descriptor.FieldDescriptor(
+      name='int_val', full_name='gnmi.TypedValue.int_val', index=1,
+      number=2, type=3, cpp_type=2, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    _descriptor.FieldDescriptor(
+      name='uint_val', full_name='gnmi.TypedValue.uint_val', index=2,
+      number=3, type=4, cpp_type=4, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    _descriptor.FieldDescriptor(
+      name='bool_val', full_name='gnmi.TypedValue.bool_val', index=3,
+      number=4, type=8, cpp_type=7, label=1,
+      has_default_value=False, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    _descriptor.FieldDescriptor(
+      name='bytes_val', full_name='gnmi.TypedValue.bytes_val', index=4,
+      number=5, type=12, cpp_type=9, label=1,
+      has_default_value=False, default_value=_b(""),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    _descriptor.FieldDescriptor(
+      name='float_val', full_name='gnmi.TypedValue.float_val', index=5,
+      number=6, type=2, cpp_type=6, label=1,
+      has_default_value=False, default_value=float(0),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    _descriptor.FieldDescriptor(
+      name='decimal_val', full_name='gnmi.TypedValue.decimal_val', index=6,
+      number=7, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    _descriptor.FieldDescriptor(
+      name='leaflist_val', full_name='gnmi.TypedValue.leaflist_val', index=7,
+      number=8, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    _descriptor.FieldDescriptor(
+      name='any_val', full_name='gnmi.TypedValue.any_val', index=8,
+      number=9, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    _descriptor.FieldDescriptor(
+      name='json_val', full_name='gnmi.TypedValue.json_val', index=9,
+      number=10, type=12, cpp_type=9, label=1,
+      has_default_value=False, default_value=_b(""),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    _descriptor.FieldDescriptor(
+      name='json_ietf_val', full_name='gnmi.TypedValue.json_ietf_val', index=10,
+      number=11, type=12, cpp_type=9, label=1,
+      has_default_value=False, default_value=_b(""),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    _descriptor.FieldDescriptor(
+      name='ascii_val', full_name='gnmi.TypedValue.ascii_val', index=11,
+      number=12, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=_b("").decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+    _descriptor.OneofDescriptor(
+      name='value', full_name='gnmi.TypedValue.value',
+      index=0, containing_type=None, fields=[]),
+  ],
+  serialized_start=349,
+  serialized_end=683,
+)
+
+
+_PATH = _descriptor.Descriptor(
+  name='Path',
+  full_name='gnmi.Path',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='element', full_name='gnmi.Path.element', index=0,
+      number=1, type=9, cpp_type=9, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=_descriptor._ParseOptions(descriptor_pb2.FieldOptions(), _b('\030\001'))),
+    _descriptor.FieldDescriptor(
+      name='origin', full_name='gnmi.Path.origin', index=1,
+      number=2, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=_b("").decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    _descriptor.FieldDescriptor(
+      name='elem', full_name='gnmi.Path.elem', index=2,
+      number=3, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    _descriptor.FieldDescriptor(
+      name='target', full_name='gnmi.Path.target', index=3,
+      number=4, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=_b("").decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=685,
+  serialized_end=774,
+)
+
+
+_PATHELEM_KEYENTRY = _descriptor.Descriptor(
+  name='KeyEntry',
+  full_name='gnmi.PathElem.KeyEntry',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='key', full_name='gnmi.PathElem.KeyEntry.key', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=_b("").decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    _descriptor.FieldDescriptor(
+      name='value', full_name='gnmi.PathElem.KeyEntry.value', index=1,
+      number=2, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=_b("").decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  options=_descriptor._ParseOptions(descriptor_pb2.MessageOptions(), _b('8\001')),
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=840,
+  serialized_end=882,
+)
+
+_PATHELEM = _descriptor.Descriptor(
+  name='PathElem',
+  full_name='gnmi.PathElem',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='name', full_name='gnmi.PathElem.name', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=_b("").decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    _descriptor.FieldDescriptor(
+      name='key', full_name='gnmi.PathElem.key', index=1,
+      number=2, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+  ],
+  extensions=[
+  ],
+  nested_types=[_PATHELEM_KEYENTRY, ],
+  enum_types=[
+  ],
+  options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=776,
+  serialized_end=882,
+)
+
+
+_VALUE = _descriptor.Descriptor(
+  name='Value',
+  full_name='gnmi.Value',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='value', full_name='gnmi.Value.value', index=0,
+      number=1, type=12, cpp_type=9, label=1,
+      has_default_value=False, default_value=_b(""),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    _descriptor.FieldDescriptor(
+      name='type', full_name='gnmi.Value.type', index=1,
+      number=2, type=14, cpp_type=8, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  options=_descriptor._ParseOptions(descriptor_pb2.MessageOptions(), _b('\030\001')),
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=884,
+  serialized_end=940,
+)
+
+
+_ERROR = _descriptor.Descriptor(
+  name='Error',
+  full_name='gnmi.Error',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='code', full_name='gnmi.Error.code', index=0,
+      number=1, type=13, cpp_type=3, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    _descriptor.FieldDescriptor(
+      name='message', full_name='gnmi.Error.message', index=1,
+      number=2, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=_b("").decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    _descriptor.FieldDescriptor(
+      name='data', full_name='gnmi.Error.data', index=2,
+      number=3, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  options=_descriptor._ParseOptions(descriptor_pb2.MessageOptions(), _b('\030\001')),
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=942,
+  serialized_end=1020,
+)
+
+
+_DECIMAL64 = _descriptor.Descriptor(
+  name='Decimal64',
+  full_name='gnmi.Decimal64',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='digits', full_name='gnmi.Decimal64.digits', index=0,
+      number=1, type=4, cpp_type=4, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    _descriptor.FieldDescriptor(
+      name='precision', full_name='gnmi.Decimal64.precision', index=1,
+      number=2, type=13, cpp_type=3, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1022,
+  serialized_end=1068,
+)
+
+
+_SCALARARRAY = _descriptor.Descriptor(
+  name='ScalarArray',
+  full_name='gnmi.ScalarArray',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='element', full_name='gnmi.ScalarArray.element', index=0,
+      number=1, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1070,
+  serialized_end=1118,
+)
+
+
+_SUBSCRIBEREQUEST = _descriptor.Descriptor(
+  name='SubscribeRequest',
+  full_name='gnmi.SubscribeRequest',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='subscribe', full_name='gnmi.SubscribeRequest.subscribe', index=0,
+      number=1, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    _descriptor.FieldDescriptor(
+      name='poll', full_name='gnmi.SubscribeRequest.poll', index=1,
+      number=3, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    _descriptor.FieldDescriptor(
+      name='aliases', full_name='gnmi.SubscribeRequest.aliases', index=2,
+      number=4, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+    _descriptor.OneofDescriptor(
+      name='request', full_name='gnmi.SubscribeRequest.request',
+      index=0, containing_type=None, fields=[]),
+  ],
+  serialized_start=1121,
+  serialized_end=1259,
+)
+
+
+_POLL = _descriptor.Descriptor(
+  name='Poll',
+  full_name='gnmi.Poll',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1261,
+  serialized_end=1267,
+)
+
+
+_SUBSCRIBERESPONSE = _descriptor.Descriptor(
+  name='SubscribeResponse',
+  full_name='gnmi.SubscribeResponse',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='update', full_name='gnmi.SubscribeResponse.update', index=0,
+      number=1, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    _descriptor.FieldDescriptor(
+      name='sync_response', full_name='gnmi.SubscribeResponse.sync_response', index=1,
+      number=3, type=8, cpp_type=7, label=1,
+      has_default_value=False, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    _descriptor.FieldDescriptor(
+      name='error', full_name='gnmi.SubscribeResponse.error', index=2,
+      number=4, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=_descriptor._ParseOptions(descriptor_pb2.FieldOptions(), _b('\030\001'))),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+    _descriptor.OneofDescriptor(
+      name='response', full_name='gnmi.SubscribeResponse.response',
+      index=0, containing_type=None, fields=[]),
+  ],
+  serialized_start=1270,
+  serialized_end=1398,
+)
+
+
+_SUBSCRIPTIONLIST = _descriptor.Descriptor(
+  name='SubscriptionList',
+  full_name='gnmi.SubscriptionList',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='prefix', full_name='gnmi.SubscriptionList.prefix', index=0,
+      number=1, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    _descriptor.FieldDescriptor(
+      name='subscription', full_name='gnmi.SubscriptionList.subscription', index=1,
+      number=2, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    _descriptor.FieldDescriptor(
+      name='use_aliases', full_name='gnmi.SubscriptionList.use_aliases', index=2,
+      number=3, type=8, cpp_type=7, label=1,
+      has_default_value=False, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    _descriptor.FieldDescriptor(
+      name='qos', full_name='gnmi.SubscriptionList.qos', index=3,
+      number=4, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    _descriptor.FieldDescriptor(
+      name='mode', full_name='gnmi.SubscriptionList.mode', index=4,
+      number=5, type=14, cpp_type=8, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    _descriptor.FieldDescriptor(
+      name='allow_aggregation', full_name='gnmi.SubscriptionList.allow_aggregation', index=5,
+      number=6, type=8, cpp_type=7, label=1,
+      has_default_value=False, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    _descriptor.FieldDescriptor(
+      name='use_models', full_name='gnmi.SubscriptionList.use_models', index=6,
+      number=7, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    _descriptor.FieldDescriptor(
+      name='encoding', full_name='gnmi.SubscriptionList.encoding', index=7,
+      number=8, type=14, cpp_type=8, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    _descriptor.FieldDescriptor(
+      name='updates_only', full_name='gnmi.SubscriptionList.updates_only', index=8,
+      number=9, type=8, cpp_type=7, label=1,
+      has_default_value=False, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+    _SUBSCRIPTIONLIST_MODE,
+  ],
+  options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1401,
+  serialized_end=1744,
+)
+
+
+_SUBSCRIPTION = _descriptor.Descriptor(
+  name='Subscription',
+  full_name='gnmi.Subscription',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='path', full_name='gnmi.Subscription.path', index=0,
+      number=1, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    _descriptor.FieldDescriptor(
+      name='mode', full_name='gnmi.Subscription.mode', index=1,
+      number=2, type=14, cpp_type=8, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    _descriptor.FieldDescriptor(
+      name='sample_interval', full_name='gnmi.Subscription.sample_interval', index=2,
+      number=3, type=4, cpp_type=4, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    _descriptor.FieldDescriptor(
+      name='suppress_redundant', full_name='gnmi.Subscription.suppress_redundant', index=3,
+      number=4, type=8, cpp_type=7, label=1,
+      has_default_value=False, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    _descriptor.FieldDescriptor(
+      name='heartbeat_interval', full_name='gnmi.Subscription.heartbeat_interval', index=4,
+      number=5, type=4, cpp_type=4, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1747,
+  serialized_end=1906,
+)
+
+
+_QOSMARKING = _descriptor.Descriptor(
+  name='QOSMarking',
+  full_name='gnmi.QOSMarking',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='marking', full_name='gnmi.QOSMarking.marking', index=0,
+      number=1, type=13, cpp_type=3, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1908,
+  serialized_end=1937,
+)
+
+
+_ALIAS = _descriptor.Descriptor(
+  name='Alias',
+  full_name='gnmi.Alias',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='path', full_name='gnmi.Alias.path', index=0,
+      number=1, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    _descriptor.FieldDescriptor(
+      name='alias', full_name='gnmi.Alias.alias', index=1,
+      number=2, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=_b("").decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1939,
+  serialized_end=1987,
+)
+
+
+_ALIASLIST = _descriptor.Descriptor(
+  name='AliasList',
+  full_name='gnmi.AliasList',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='alias', full_name='gnmi.AliasList.alias', index=0,
+      number=1, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1989,
+  serialized_end=2028,
+)
+
+
+_SETREQUEST = _descriptor.Descriptor(
+  name='SetRequest',
+  full_name='gnmi.SetRequest',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='prefix', full_name='gnmi.SetRequest.prefix', index=0,
+      number=1, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    _descriptor.FieldDescriptor(
+      name='delete', full_name='gnmi.SetRequest.delete', index=1,
+      number=2, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    _descriptor.FieldDescriptor(
+      name='replace', full_name='gnmi.SetRequest.replace', index=2,
+      number=3, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    _descriptor.FieldDescriptor(
+      name='update', full_name='gnmi.SetRequest.update', index=3,
+      number=4, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=2031,
+  serialized_end=2160,
+)
+
+
+_SETRESPONSE = _descriptor.Descriptor(
+  name='SetResponse',
+  full_name='gnmi.SetResponse',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='prefix', full_name='gnmi.SetResponse.prefix', index=0,
+      number=1, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    _descriptor.FieldDescriptor(
+      name='response', full_name='gnmi.SetResponse.response', index=1,
+      number=2, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    _descriptor.FieldDescriptor(
+      name='message', full_name='gnmi.SetResponse.message', index=2,
+      number=3, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=_descriptor._ParseOptions(descriptor_pb2.FieldOptions(), _b('\030\001'))),
+    _descriptor.FieldDescriptor(
+      name='timestamp', full_name='gnmi.SetResponse.timestamp', index=3,
+      number=4, type=3, cpp_type=2, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=2163,
+  serialized_end=2295,
+)
+
+
+_UPDATERESULT = _descriptor.Descriptor(
+  name='UpdateResult',
+  full_name='gnmi.UpdateResult',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='timestamp', full_name='gnmi.UpdateResult.timestamp', index=0,
+      number=1, type=3, cpp_type=2, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=_descriptor._ParseOptions(descriptor_pb2.FieldOptions(), _b('\030\001'))),
+    _descriptor.FieldDescriptor(
+      name='path', full_name='gnmi.UpdateResult.path', index=1,
+      number=2, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    _descriptor.FieldDescriptor(
+      name='message', full_name='gnmi.UpdateResult.message', index=2,
+      number=3, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=_descriptor._ParseOptions(descriptor_pb2.FieldOptions(), _b('\030\001'))),
+    _descriptor.FieldDescriptor(
+      name='op', full_name='gnmi.UpdateResult.op', index=3,
+      number=4, type=14, cpp_type=8, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+    _UPDATERESULT_OPERATION,
+  ],
+  options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=2298,
+  serialized_end=2500,
+)
+
+
+_GETREQUEST = _descriptor.Descriptor(
+  name='GetRequest',
+  full_name='gnmi.GetRequest',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='prefix', full_name='gnmi.GetRequest.prefix', index=0,
+      number=1, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    _descriptor.FieldDescriptor(
+      name='path', full_name='gnmi.GetRequest.path', index=1,
+      number=2, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    _descriptor.FieldDescriptor(
+      name='type', full_name='gnmi.GetRequest.type', index=2,
+      number=3, type=14, cpp_type=8, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    _descriptor.FieldDescriptor(
+      name='encoding', full_name='gnmi.GetRequest.encoding', index=3,
+      number=5, type=14, cpp_type=8, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    _descriptor.FieldDescriptor(
+      name='use_models', full_name='gnmi.GetRequest.use_models', index=4,
+      number=6, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+    _GETREQUEST_DATATYPE,
+  ],
+  options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=2503,
+  serialized_end=2742,
+)
+
+
+_GETRESPONSE = _descriptor.Descriptor(
+  name='GetResponse',
+  full_name='gnmi.GetResponse',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='notification', full_name='gnmi.GetResponse.notification', index=0,
+      number=1, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    _descriptor.FieldDescriptor(
+      name='error', full_name='gnmi.GetResponse.error', index=1,
+      number=2, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=_descriptor._ParseOptions(descriptor_pb2.FieldOptions(), _b('\030\001'))),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=2744,
+  serialized_end=2831,
+)
+
+
+_CAPABILITYREQUEST = _descriptor.Descriptor(
+  name='CapabilityRequest',
+  full_name='gnmi.CapabilityRequest',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=2833,
+  serialized_end=2852,
+)
+
+
+_CAPABILITYRESPONSE = _descriptor.Descriptor(
+  name='CapabilityResponse',
+  full_name='gnmi.CapabilityResponse',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='supported_models', full_name='gnmi.CapabilityResponse.supported_models', index=0,
+      number=1, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    _descriptor.FieldDescriptor(
+      name='supported_encodings', full_name='gnmi.CapabilityResponse.supported_encodings', index=1,
+      number=2, type=14, cpp_type=8, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    _descriptor.FieldDescriptor(
+      name='gNMI_version', full_name='gnmi.CapabilityResponse.gNMI_version', index=2,
+      number=3, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=_b("").decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=2855,
+  serialized_end=2985,
+)
+
+
+_MODELDATA = _descriptor.Descriptor(
+  name='ModelData',
+  full_name='gnmi.ModelData',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='name', full_name='gnmi.ModelData.name', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=_b("").decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    _descriptor.FieldDescriptor(
+      name='organization', full_name='gnmi.ModelData.organization', index=1,
+      number=2, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=_b("").decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    _descriptor.FieldDescriptor(
+      name='version', full_name='gnmi.ModelData.version', index=2,
+      number=3, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=_b("").decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=2987,
+  serialized_end=3051,
+)
+
+_NOTIFICATION.fields_by_name['prefix'].message_type = _PATH
+_NOTIFICATION.fields_by_name['update'].message_type = _UPDATE
+_NOTIFICATION.fields_by_name['delete'].message_type = _PATH
+_UPDATE.fields_by_name['path'].message_type = _PATH
+_UPDATE.fields_by_name['value'].message_type = _VALUE
+_UPDATE.fields_by_name['val'].message_type = _TYPEDVALUE
+_TYPEDVALUE.fields_by_name['decimal_val'].message_type = _DECIMAL64
+_TYPEDVALUE.fields_by_name['leaflist_val'].message_type = _SCALARARRAY
+_TYPEDVALUE.fields_by_name['any_val'].message_type = google_dot_protobuf_dot_any__pb2._ANY
+_TYPEDVALUE.oneofs_by_name['value'].fields.append(
+  _TYPEDVALUE.fields_by_name['string_val'])
+_TYPEDVALUE.fields_by_name['string_val'].containing_oneof = _TYPEDVALUE.oneofs_by_name['value']
+_TYPEDVALUE.oneofs_by_name['value'].fields.append(
+  _TYPEDVALUE.fields_by_name['int_val'])
+_TYPEDVALUE.fields_by_name['int_val'].containing_oneof = _TYPEDVALUE.oneofs_by_name['value']
+_TYPEDVALUE.oneofs_by_name['value'].fields.append(
+  _TYPEDVALUE.fields_by_name['uint_val'])
+_TYPEDVALUE.fields_by_name['uint_val'].containing_oneof = _TYPEDVALUE.oneofs_by_name['value']
+_TYPEDVALUE.oneofs_by_name['value'].fields.append(
+  _TYPEDVALUE.fields_by_name['bool_val'])
+_TYPEDVALUE.fields_by_name['bool_val'].containing_oneof = _TYPEDVALUE.oneofs_by_name['value']
+_TYPEDVALUE.oneofs_by_name['value'].fields.append(
+  _TYPEDVALUE.fields_by_name['bytes_val'])
+_TYPEDVALUE.fields_by_name['bytes_val'].containing_oneof = _TYPEDVALUE.oneofs_by_name['value']
+_TYPEDVALUE.oneofs_by_name['value'].fields.append(
+  _TYPEDVALUE.fields_by_name['float_val'])
+_TYPEDVALUE.fields_by_name['float_val'].containing_oneof = _TYPEDVALUE.oneofs_by_name['value']
+_TYPEDVALUE.oneofs_by_name['value'].fields.append(
+  _TYPEDVALUE.fields_by_name['decimal_val'])
+_TYPEDVALUE.fields_by_name['decimal_val'].containing_oneof = _TYPEDVALUE.oneofs_by_name['value']
+_TYPEDVALUE.oneofs_by_name['value'].fields.append(
+  _TYPEDVALUE.fields_by_name['leaflist_val'])
+_TYPEDVALUE.fields_by_name['leaflist_val'].containing_oneof = _TYPEDVALUE.oneofs_by_name['value']
+_TYPEDVALUE.oneofs_by_name['value'].fields.append(
+  _TYPEDVALUE.fields_by_name['any_val'])
+_TYPEDVALUE.fields_by_name['any_val'].containing_oneof = _TYPEDVALUE.oneofs_by_name['value']
+_TYPEDVALUE.oneofs_by_name['value'].fields.append(
+  _TYPEDVALUE.fields_by_name['json_val'])
+_TYPEDVALUE.fields_by_name['json_val'].containing_oneof = _TYPEDVALUE.oneofs_by_name['value']
+_TYPEDVALUE.oneofs_by_name['value'].fields.append(
+  _TYPEDVALUE.fields_by_name['json_ietf_val'])
+_TYPEDVALUE.fields_by_name['json_ietf_val'].containing_oneof = _TYPEDVALUE.oneofs_by_name['value']
+_TYPEDVALUE.oneofs_by_name['value'].fields.append(
+  _TYPEDVALUE.fields_by_name['ascii_val'])
+_TYPEDVALUE.fields_by_name['ascii_val'].containing_oneof = _TYPEDVALUE.oneofs_by_name['value']
+_PATH.fields_by_name['elem'].message_type = _PATHELEM
+_PATHELEM_KEYENTRY.containing_type = _PATHELEM
+_PATHELEM.fields_by_name['key'].message_type = _PATHELEM_KEYENTRY
+_VALUE.fields_by_name['type'].enum_type = _ENCODING
+_ERROR.fields_by_name['data'].message_type = google_dot_protobuf_dot_any__pb2._ANY
+_SCALARARRAY.fields_by_name['element'].message_type = _TYPEDVALUE
+_SUBSCRIBEREQUEST.fields_by_name['subscribe'].message_type = _SUBSCRIPTIONLIST
+_SUBSCRIBEREQUEST.fields_by_name['poll'].message_type = _POLL
+_SUBSCRIBEREQUEST.fields_by_name['aliases'].message_type = _ALIASLIST
+_SUBSCRIBEREQUEST.oneofs_by_name['request'].fields.append(
+  _SUBSCRIBEREQUEST.fields_by_name['subscribe'])
+_SUBSCRIBEREQUEST.fields_by_name['subscribe'].containing_oneof = _SUBSCRIBEREQUEST.oneofs_by_name['request']
+_SUBSCRIBEREQUEST.oneofs_by_name['request'].fields.append(
+  _SUBSCRIBEREQUEST.fields_by_name['poll'])
+_SUBSCRIBEREQUEST.fields_by_name['poll'].containing_oneof = _SUBSCRIBEREQUEST.oneofs_by_name['request']
+_SUBSCRIBEREQUEST.oneofs_by_name['request'].fields.append(
+  _SUBSCRIBEREQUEST.fields_by_name['aliases'])
+_SUBSCRIBEREQUEST.fields_by_name['aliases'].containing_oneof = _SUBSCRIBEREQUEST.oneofs_by_name['request']
+_SUBSCRIBERESPONSE.fields_by_name['update'].message_type = _NOTIFICATION
+_SUBSCRIBERESPONSE.fields_by_name['error'].message_type = _ERROR
+_SUBSCRIBERESPONSE.oneofs_by_name['response'].fields.append(
+  _SUBSCRIBERESPONSE.fields_by_name['update'])
+_SUBSCRIBERESPONSE.fields_by_name['update'].containing_oneof = _SUBSCRIBERESPONSE.oneofs_by_name['response']
+_SUBSCRIBERESPONSE.oneofs_by_name['response'].fields.append(
+  _SUBSCRIBERESPONSE.fields_by_name['sync_response'])
+_SUBSCRIBERESPONSE.fields_by_name['sync_response'].containing_oneof = _SUBSCRIBERESPONSE.oneofs_by_name['response']
+_SUBSCRIBERESPONSE.oneofs_by_name['response'].fields.append(
+  _SUBSCRIBERESPONSE.fields_by_name['error'])
+_SUBSCRIBERESPONSE.fields_by_name['error'].containing_oneof = _SUBSCRIBERESPONSE.oneofs_by_name['response']
+_SUBSCRIPTIONLIST.fields_by_name['prefix'].message_type = _PATH
+_SUBSCRIPTIONLIST.fields_by_name['subscription'].message_type = _SUBSCRIPTION
+_SUBSCRIPTIONLIST.fields_by_name['qos'].message_type = _QOSMARKING
+_SUBSCRIPTIONLIST.fields_by_name['mode'].enum_type = _SUBSCRIPTIONLIST_MODE
+_SUBSCRIPTIONLIST.fields_by_name['use_models'].message_type = _MODELDATA
+_SUBSCRIPTIONLIST.fields_by_name['encoding'].enum_type = _ENCODING
+_SUBSCRIPTIONLIST_MODE.containing_type = _SUBSCRIPTIONLIST
+_SUBSCRIPTION.fields_by_name['path'].message_type = _PATH
+_SUBSCRIPTION.fields_by_name['mode'].enum_type = _SUBSCRIPTIONMODE
+_ALIAS.fields_by_name['path'].message_type = _PATH
+_ALIASLIST.fields_by_name['alias'].message_type = _ALIAS
+_SETREQUEST.fields_by_name['prefix'].message_type = _PATH
+_SETREQUEST.fields_by_name['delete'].message_type = _PATH
+_SETREQUEST.fields_by_name['replace'].message_type = _UPDATE
+_SETREQUEST.fields_by_name['update'].message_type = _UPDATE
+_SETRESPONSE.fields_by_name['prefix'].message_type = _PATH
+_SETRESPONSE.fields_by_name['response'].message_type = _UPDATERESULT
+_SETRESPONSE.fields_by_name['message'].message_type = _ERROR
+_UPDATERESULT.fields_by_name['path'].message_type = _PATH
+_UPDATERESULT.fields_by_name['message'].message_type = _ERROR
+_UPDATERESULT.fields_by_name['op'].enum_type = _UPDATERESULT_OPERATION
+_UPDATERESULT_OPERATION.containing_type = _UPDATERESULT
+_GETREQUEST.fields_by_name['prefix'].message_type = _PATH
+_GETREQUEST.fields_by_name['path'].message_type = _PATH
+_GETREQUEST.fields_by_name['type'].enum_type = _GETREQUEST_DATATYPE
+_GETREQUEST.fields_by_name['encoding'].enum_type = _ENCODING
+_GETREQUEST.fields_by_name['use_models'].message_type = _MODELDATA
+_GETREQUEST_DATATYPE.containing_type = _GETREQUEST
+_GETRESPONSE.fields_by_name['notification'].message_type = _NOTIFICATION
+_GETRESPONSE.fields_by_name['error'].message_type = _ERROR
+_CAPABILITYRESPONSE.fields_by_name['supported_models'].message_type = _MODELDATA
+_CAPABILITYRESPONSE.fields_by_name['supported_encodings'].enum_type = _ENCODING
+DESCRIPTOR.message_types_by_name['Notification'] = _NOTIFICATION
+DESCRIPTOR.message_types_by_name['Update'] = _UPDATE
+DESCRIPTOR.message_types_by_name['TypedValue'] = _TYPEDVALUE
+DESCRIPTOR.message_types_by_name['Path'] = _PATH
+DESCRIPTOR.message_types_by_name['PathElem'] = _PATHELEM
+DESCRIPTOR.message_types_by_name['Value'] = _VALUE
+DESCRIPTOR.message_types_by_name['Error'] = _ERROR
+DESCRIPTOR.message_types_by_name['Decimal64'] = _DECIMAL64
+DESCRIPTOR.message_types_by_name['ScalarArray'] = _SCALARARRAY
+DESCRIPTOR.message_types_by_name['SubscribeRequest'] = _SUBSCRIBEREQUEST
+DESCRIPTOR.message_types_by_name['Poll'] = _POLL
+DESCRIPTOR.message_types_by_name['SubscribeResponse'] = _SUBSCRIBERESPONSE
+DESCRIPTOR.message_types_by_name['SubscriptionList'] = _SUBSCRIPTIONLIST
+DESCRIPTOR.message_types_by_name['Subscription'] = _SUBSCRIPTION
+DESCRIPTOR.message_types_by_name['QOSMarking'] = _QOSMARKING
+DESCRIPTOR.message_types_by_name['Alias'] = _ALIAS
+DESCRIPTOR.message_types_by_name['AliasList'] = _ALIASLIST
+DESCRIPTOR.message_types_by_name['SetRequest'] = _SETREQUEST
+DESCRIPTOR.message_types_by_name['SetResponse'] = _SETRESPONSE
+DESCRIPTOR.message_types_by_name['UpdateResult'] = _UPDATERESULT
+DESCRIPTOR.message_types_by_name['GetRequest'] = _GETREQUEST
+DESCRIPTOR.message_types_by_name['GetResponse'] = _GETRESPONSE
+DESCRIPTOR.message_types_by_name['CapabilityRequest'] = _CAPABILITYREQUEST
+DESCRIPTOR.message_types_by_name['CapabilityResponse'] = _CAPABILITYRESPONSE
+DESCRIPTOR.message_types_by_name['ModelData'] = _MODELDATA
+DESCRIPTOR.enum_types_by_name['Encoding'] = _ENCODING
+DESCRIPTOR.enum_types_by_name['SubscriptionMode'] = _SUBSCRIPTIONMODE
+DESCRIPTOR.extensions_by_name['gnmi_service'] = gnmi_service
+_sym_db.RegisterFileDescriptor(DESCRIPTOR)
+
+Notification = _reflection.GeneratedProtocolMessageType('Notification', (_message.Message,), dict(
+  DESCRIPTOR = _NOTIFICATION,
+  __module__ = 'proto.gnmi.gnmi_pb2'
+  # @@protoc_insertion_point(class_scope:gnmi.Notification)
+  ))
+_sym_db.RegisterMessage(Notification)
+
+Update = _reflection.GeneratedProtocolMessageType('Update', (_message.Message,), dict(
+  DESCRIPTOR = _UPDATE,
+  __module__ = 'proto.gnmi.gnmi_pb2'
+  # @@protoc_insertion_point(class_scope:gnmi.Update)
+  ))
+_sym_db.RegisterMessage(Update)
+
+TypedValue = _reflection.GeneratedProtocolMessageType('TypedValue', (_message.Message,), dict(
+  DESCRIPTOR = _TYPEDVALUE,
+  __module__ = 'proto.gnmi.gnmi_pb2'
+  # @@protoc_insertion_point(class_scope:gnmi.TypedValue)
+  ))
+_sym_db.RegisterMessage(TypedValue)
+
+Path = _reflection.GeneratedProtocolMessageType('Path', (_message.Message,), dict(
+  DESCRIPTOR = _PATH,
+  __module__ = 'proto.gnmi.gnmi_pb2'
+  # @@protoc_insertion_point(class_scope:gnmi.Path)
+  ))
+_sym_db.RegisterMessage(Path)
+
+PathElem = _reflection.GeneratedProtocolMessageType('PathElem', (_message.Message,), dict(
+
+  KeyEntry = _reflection.GeneratedProtocolMessageType('KeyEntry', (_message.Message,), dict(
+    DESCRIPTOR = _PATHELEM_KEYENTRY,
+    __module__ = 'proto.gnmi.gnmi_pb2'
+    # @@protoc_insertion_point(class_scope:gnmi.PathElem.KeyEntry)
+    ))
+  ,
+  DESCRIPTOR = _PATHELEM,
+  __module__ = 'proto.gnmi.gnmi_pb2'
+  # @@protoc_insertion_point(class_scope:gnmi.PathElem)
+  ))
+_sym_db.RegisterMessage(PathElem)
+_sym_db.RegisterMessage(PathElem.KeyEntry)
+
+Value = _reflection.GeneratedProtocolMessageType('Value', (_message.Message,), dict(
+  DESCRIPTOR = _VALUE,
+  __module__ = 'proto.gnmi.gnmi_pb2'
+  # @@protoc_insertion_point(class_scope:gnmi.Value)
+  ))
+_sym_db.RegisterMessage(Value)
+
+Error = _reflection.GeneratedProtocolMessageType('Error', (_message.Message,), dict(
+  DESCRIPTOR = _ERROR,
+  __module__ = 'proto.gnmi.gnmi_pb2'
+  # @@protoc_insertion_point(class_scope:gnmi.Error)
+  ))
+_sym_db.RegisterMessage(Error)
+
+Decimal64 = _reflection.GeneratedProtocolMessageType('Decimal64', (_message.Message,), dict(
+  DESCRIPTOR = _DECIMAL64,
+  __module__ = 'proto.gnmi.gnmi_pb2'
+  # @@protoc_insertion_point(class_scope:gnmi.Decimal64)
+  ))
+_sym_db.RegisterMessage(Decimal64)
+
+ScalarArray = _reflection.GeneratedProtocolMessageType('ScalarArray', (_message.Message,), dict(
+  DESCRIPTOR = _SCALARARRAY,
+  __module__ = 'proto.gnmi.gnmi_pb2'
+  # @@protoc_insertion_point(class_scope:gnmi.ScalarArray)
+  ))
+_sym_db.RegisterMessage(ScalarArray)
+
+SubscribeRequest = _reflection.GeneratedProtocolMessageType('SubscribeRequest', (_message.Message,), dict(
+  DESCRIPTOR = _SUBSCRIBEREQUEST,
+  __module__ = 'proto.gnmi.gnmi_pb2'
+  # @@protoc_insertion_point(class_scope:gnmi.SubscribeRequest)
+  ))
+_sym_db.RegisterMessage(SubscribeRequest)
+
+Poll = _reflection.GeneratedProtocolMessageType('Poll', (_message.Message,), dict(
+  DESCRIPTOR = _POLL,
+  __module__ = 'proto.gnmi.gnmi_pb2'
+  # @@protoc_insertion_point(class_scope:gnmi.Poll)
+  ))
+_sym_db.RegisterMessage(Poll)
+
+SubscribeResponse = _reflection.GeneratedProtocolMessageType('SubscribeResponse', (_message.Message,), dict(
+  DESCRIPTOR = _SUBSCRIBERESPONSE,
+  __module__ = 'proto.gnmi.gnmi_pb2'
+  # @@protoc_insertion_point(class_scope:gnmi.SubscribeResponse)
+  ))
+_sym_db.RegisterMessage(SubscribeResponse)
+
+SubscriptionList = _reflection.GeneratedProtocolMessageType('SubscriptionList', (_message.Message,), dict(
+  DESCRIPTOR = _SUBSCRIPTIONLIST,
+  __module__ = 'proto.gnmi.gnmi_pb2'
+  # @@protoc_insertion_point(class_scope:gnmi.SubscriptionList)
+  ))
+_sym_db.RegisterMessage(SubscriptionList)
+
+Subscription = _reflection.GeneratedProtocolMessageType('Subscription', (_message.Message,), dict(
+  DESCRIPTOR = _SUBSCRIPTION,
+  __module__ = 'proto.gnmi.gnmi_pb2'
+  # @@protoc_insertion_point(class_scope:gnmi.Subscription)
+  ))
+_sym_db.RegisterMessage(Subscription)
+
+QOSMarking = _reflection.GeneratedProtocolMessageType('QOSMarking', (_message.Message,), dict(
+  DESCRIPTOR = _QOSMARKING,
+  __module__ = 'proto.gnmi.gnmi_pb2'
+  # @@protoc_insertion_point(class_scope:gnmi.QOSMarking)
+  ))
+_sym_db.RegisterMessage(QOSMarking)
+
+Alias = _reflection.GeneratedProtocolMessageType('Alias', (_message.Message,), dict(
+  DESCRIPTOR = _ALIAS,
+  __module__ = 'proto.gnmi.gnmi_pb2'
+  # @@protoc_insertion_point(class_scope:gnmi.Alias)
+  ))
+_sym_db.RegisterMessage(Alias)
+
+AliasList = _reflection.GeneratedProtocolMessageType('AliasList', (_message.Message,), dict(
+  DESCRIPTOR = _ALIASLIST,
+  __module__ = 'proto.gnmi.gnmi_pb2'
+  # @@protoc_insertion_point(class_scope:gnmi.AliasList)
+  ))
+_sym_db.RegisterMessage(AliasList)
+
+SetRequest = _reflection.GeneratedProtocolMessageType('SetRequest', (_message.Message,), dict(
+  DESCRIPTOR = _SETREQUEST,
+  __module__ = 'proto.gnmi.gnmi_pb2'
+  # @@protoc_insertion_point(class_scope:gnmi.SetRequest)
+  ))
+_sym_db.RegisterMessage(SetRequest)
+
+SetResponse = _reflection.GeneratedProtocolMessageType('SetResponse', (_message.Message,), dict(
+  DESCRIPTOR = _SETRESPONSE,
+  __module__ = 'proto.gnmi.gnmi_pb2'
+  # @@protoc_insertion_point(class_scope:gnmi.SetResponse)
+  ))
+_sym_db.RegisterMessage(SetResponse)
+
+UpdateResult = _reflection.GeneratedProtocolMessageType('UpdateResult', (_message.Message,), dict(
+  DESCRIPTOR = _UPDATERESULT,
+  __module__ = 'proto.gnmi.gnmi_pb2'
+  # @@protoc_insertion_point(class_scope:gnmi.UpdateResult)
+  ))
+_sym_db.RegisterMessage(UpdateResult)
+
+GetRequest = _reflection.GeneratedProtocolMessageType('GetRequest', (_message.Message,), dict(
+  DESCRIPTOR = _GETREQUEST,
+  __module__ = 'proto.gnmi.gnmi_pb2'
+  # @@protoc_insertion_point(class_scope:gnmi.GetRequest)
+  ))
+_sym_db.RegisterMessage(GetRequest)
+
+GetResponse = _reflection.GeneratedProtocolMessageType('GetResponse', (_message.Message,), dict(
+  DESCRIPTOR = _GETRESPONSE,
+  __module__ = 'proto.gnmi.gnmi_pb2'
+  # @@protoc_insertion_point(class_scope:gnmi.GetResponse)
+  ))
+_sym_db.RegisterMessage(GetResponse)
+
+CapabilityRequest = _reflection.GeneratedProtocolMessageType('CapabilityRequest', (_message.Message,), dict(
+  DESCRIPTOR = _CAPABILITYREQUEST,
+  __module__ = 'proto.gnmi.gnmi_pb2'
+  # @@protoc_insertion_point(class_scope:gnmi.CapabilityRequest)
+  ))
+_sym_db.RegisterMessage(CapabilityRequest)
+
+CapabilityResponse = _reflection.GeneratedProtocolMessageType('CapabilityResponse', (_message.Message,), dict(
+  DESCRIPTOR = _CAPABILITYRESPONSE,
+  __module__ = 'proto.gnmi.gnmi_pb2'
+  # @@protoc_insertion_point(class_scope:gnmi.CapabilityResponse)
+  ))
+_sym_db.RegisterMessage(CapabilityResponse)
+
+ModelData = _reflection.GeneratedProtocolMessageType('ModelData', (_message.Message,), dict(
+  DESCRIPTOR = _MODELDATA,
+  __module__ = 'proto.gnmi.gnmi_pb2'
+  # @@protoc_insertion_point(class_scope:gnmi.ModelData)
+  ))
+_sym_db.RegisterMessage(ModelData)
+
+google_dot_protobuf_dot_descriptor__pb2.FileOptions.RegisterExtension(gnmi_service)
+
+DESCRIPTOR.has_options = True
+DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), _b('\312>\0050.5.0'))
+_UPDATE.fields_by_name['value'].has_options = True
+_UPDATE.fields_by_name['value']._options = _descriptor._ParseOptions(descriptor_pb2.FieldOptions(), _b('\030\001'))
+_PATH.fields_by_name['element'].has_options = True
+_PATH.fields_by_name['element']._options = _descriptor._ParseOptions(descriptor_pb2.FieldOptions(), _b('\030\001'))
+_PATHELEM_KEYENTRY.has_options = True
+_PATHELEM_KEYENTRY._options = _descriptor._ParseOptions(descriptor_pb2.MessageOptions(), _b('8\001'))
+_VALUE.has_options = True
+_VALUE._options = _descriptor._ParseOptions(descriptor_pb2.MessageOptions(), _b('\030\001'))
+_ERROR.has_options = True
+_ERROR._options = _descriptor._ParseOptions(descriptor_pb2.MessageOptions(), _b('\030\001'))
+_SUBSCRIBERESPONSE.fields_by_name['error'].has_options = True
+_SUBSCRIBERESPONSE.fields_by_name['error']._options = _descriptor._ParseOptions(descriptor_pb2.FieldOptions(), _b('\030\001'))
+_SETRESPONSE.fields_by_name['message'].has_options = True
+_SETRESPONSE.fields_by_name['message']._options = _descriptor._ParseOptions(descriptor_pb2.FieldOptions(), _b('\030\001'))
+_UPDATERESULT.fields_by_name['timestamp'].has_options = True
+_UPDATERESULT.fields_by_name['timestamp']._options = _descriptor._ParseOptions(descriptor_pb2.FieldOptions(), _b('\030\001'))
+_UPDATERESULT.fields_by_name['message'].has_options = True
+_UPDATERESULT.fields_by_name['message']._options = _descriptor._ParseOptions(descriptor_pb2.FieldOptions(), _b('\030\001'))
+_GETRESPONSE.fields_by_name['error'].has_options = True
+_GETRESPONSE.fields_by_name['error']._options = _descriptor._ParseOptions(descriptor_pb2.FieldOptions(), _b('\030\001'))
+try:
+  # THESE ELEMENTS WILL BE DEPRECATED.
+  # Please use the generated *_pb2_grpc.py files instead.
+  import grpc
+  from grpc.beta import implementations as beta_implementations
+  from grpc.beta import interfaces as beta_interfaces
+  from grpc.framework.common import cardinality
+  from grpc.framework.interfaces.face import utilities as face_utilities
+
+
+  class gNMIStub(object):
+    # missing associated documentation comment in .proto file
+    pass
+
+    def __init__(self, channel):
+      """Constructor.
+
+      Args:
+        channel: A grpc.Channel.
+      """
+      self.Capabilities = channel.unary_unary(
+          '/gnmi.gNMI/Capabilities',
+          request_serializer=CapabilityRequest.SerializeToString,
+          response_deserializer=CapabilityResponse.FromString,
+          )
+      self.Get = channel.unary_unary(
+          '/gnmi.gNMI/Get',
+          request_serializer=GetRequest.SerializeToString,
+          response_deserializer=GetResponse.FromString,
+          )
+      self.Set = channel.unary_unary(
+          '/gnmi.gNMI/Set',
+          request_serializer=SetRequest.SerializeToString,
+          response_deserializer=SetResponse.FromString,
+          )
+      self.Subscribe = channel.stream_stream(
+          '/gnmi.gNMI/Subscribe',
+          request_serializer=SubscribeRequest.SerializeToString,
+          response_deserializer=SubscribeResponse.FromString,
+          )
+
+
+  class gNMIServicer(object):
+    # missing associated documentation comment in .proto file
+    pass
+
+    def Capabilities(self, request, context):
+      """Capabilities allows the client to retrieve the set of capabilities that
+      is supported by the target. This allows the target to validate the
+      service version that is implemented and retrieve the set of models that
+      the target supports. The models can then be specified in subsequent RPCs
+      to restrict the set of data that is utilized.
+      Reference: gNMI Specification Section 3.2
+      """
+      context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+      context.set_details('Method not implemented!')
+      raise NotImplementedError('Method not implemented!')
+
+    def Get(self, request, context):
+      """Retrieve a snapshot of data from the target. A Get RPC requests that the
+      target snapshots a subset of the data tree as specified by the paths
+      included in the message and serializes this to be returned to the
+      client using the specified encoding.
+      Reference: gNMI Specification Section 3.3
+      """
+      context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+      context.set_details('Method not implemented!')
+      raise NotImplementedError('Method not implemented!')
+
+    def Set(self, request, context):
+      """Set allows the client to modify the state of data on the target. The
+      paths to modified along with the new values that the client wishes
+      to set the value to.
+      Reference: gNMI Specification Section 3.4
+      """
+      context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+      context.set_details('Method not implemented!')
+      raise NotImplementedError('Method not implemented!')
+
+    def Subscribe(self, request_iterator, context):
+      """Subscribe allows a client to request the target to send it values
+      of particular paths within the data tree. These values may be streamed
+      at a particular cadence (STREAM), sent one off on a long-lived channel
+      (POLL), or sent as a one-off retrieval (ONCE).
+      Reference: gNMI Specification Section 3.5
+      """
+      context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+      context.set_details('Method not implemented!')
+      raise NotImplementedError('Method not implemented!')
+
+
+  def add_gNMIServicer_to_server(servicer, server):
+    rpc_method_handlers = {
+        'Capabilities': grpc.unary_unary_rpc_method_handler(
+            servicer.Capabilities,
+            request_deserializer=CapabilityRequest.FromString,
+            response_serializer=CapabilityResponse.SerializeToString,
+        ),
+        'Get': grpc.unary_unary_rpc_method_handler(
+            servicer.Get,
+            request_deserializer=GetRequest.FromString,
+            response_serializer=GetResponse.SerializeToString,
+        ),
+        'Set': grpc.unary_unary_rpc_method_handler(
+            servicer.Set,
+            request_deserializer=SetRequest.FromString,
+            response_serializer=SetResponse.SerializeToString,
+        ),
+        'Subscribe': grpc.stream_stream_rpc_method_handler(
+            servicer.Subscribe,
+            request_deserializer=SubscribeRequest.FromString,
+            response_serializer=SubscribeResponse.SerializeToString,
+        ),
+    }
+    generic_handler = grpc.method_handlers_generic_handler(
+        'gnmi.gNMI', rpc_method_handlers)
+    server.add_generic_rpc_handlers((generic_handler,))
+
+
+  class BetagNMIServicer(object):
+    """The Beta API is deprecated for 0.15.0 and later.
+
+    It is recommended to use the GA API (classes and functions in this
+    file not marked beta) for all further purposes. This class was generated
+    only to ease transition from grpcio<0.15.0 to grpcio>=0.15.0."""
+    # missing associated documentation comment in .proto file
+    pass
+    def Capabilities(self, request, context):
+      """Capabilities allows the client to retrieve the set of capabilities that
+      is supported by the target. This allows the target to validate the
+      service version that is implemented and retrieve the set of models that
+      the target supports. The models can then be specified in subsequent RPCs
+      to restrict the set of data that is utilized.
+      Reference: gNMI Specification Section 3.2
+      """
+      context.code(beta_interfaces.StatusCode.UNIMPLEMENTED)
+    def Get(self, request, context):
+      """Retrieve a snapshot of data from the target. A Get RPC requests that the
+      target snapshots a subset of the data tree as specified by the paths
+      included in the message and serializes this to be returned to the
+      client using the specified encoding.
+      Reference: gNMI Specification Section 3.3
+      """
+      context.code(beta_interfaces.StatusCode.UNIMPLEMENTED)
+    def Set(self, request, context):
+      """Set allows the client to modify the state of data on the target. The
+      paths to modified along with the new values that the client wishes
+      to set the value to.
+      Reference: gNMI Specification Section 3.4
+      """
+      context.code(beta_interfaces.StatusCode.UNIMPLEMENTED)
+    def Subscribe(self, request_iterator, context):
+      """Subscribe allows a client to request the target to send it values
+      of particular paths within the data tree. These values may be streamed
+      at a particular cadence (STREAM), sent one off on a long-lived channel
+      (POLL), or sent as a one-off retrieval (ONCE).
+      Reference: gNMI Specification Section 3.5
+      """
+      context.code(beta_interfaces.StatusCode.UNIMPLEMENTED)
+
+
+  class BetagNMIStub(object):
+    """The Beta API is deprecated for 0.15.0 and later.
+
+    It is recommended to use the GA API (classes and functions in this
+    file not marked beta) for all further purposes. This class was generated
+    only to ease transition from grpcio<0.15.0 to grpcio>=0.15.0."""
+    # missing associated documentation comment in .proto file
+    pass
+    def Capabilities(self, request, timeout, metadata=None, with_call=False, protocol_options=None):
+      """Capabilities allows the client to retrieve the set of capabilities that
+      is supported by the target. This allows the target to validate the
+      service version that is implemented and retrieve the set of models that
+      the target supports. The models can then be specified in subsequent RPCs
+      to restrict the set of data that is utilized.
+      Reference: gNMI Specification Section 3.2
+      """
+      raise NotImplementedError()
+    Capabilities.future = None
+    def Get(self, request, timeout, metadata=None, with_call=False, protocol_options=None):
+      """Retrieve a snapshot of data from the target. A Get RPC requests that the
+      target snapshots a subset of the data tree as specified by the paths
+      included in the message and serializes this to be returned to the
+      client using the specified encoding.
+      Reference: gNMI Specification Section 3.3
+      """
+      raise NotImplementedError()
+    Get.future = None
+    def Set(self, request, timeout, metadata=None, with_call=False, protocol_options=None):
+      """Set allows the client to modify the state of data on the target. The
+      paths to modified along with the new values that the client wishes
+      to set the value to.
+      Reference: gNMI Specification Section 3.4
+      """
+      raise NotImplementedError()
+    Set.future = None
+    def Subscribe(self, request_iterator, timeout, metadata=None, with_call=False, protocol_options=None):
+      """Subscribe allows a client to request the target to send it values
+      of particular paths within the data tree. These values may be streamed
+      at a particular cadence (STREAM), sent one off on a long-lived channel
+      (POLL), or sent as a one-off retrieval (ONCE).
+      Reference: gNMI Specification Section 3.5
+      """
+      raise NotImplementedError()
+
+
+  def beta_create_gNMI_server(servicer, pool=None, pool_size=None, default_timeout=None, maximum_timeout=None):
+    """The Beta API is deprecated for 0.15.0 and later.
+
+    It is recommended to use the GA API (classes and functions in this
+    file not marked beta) for all further purposes. This function was
+    generated only to ease transition from grpcio<0.15.0 to grpcio>=0.15.0"""
+    request_deserializers = {
+      ('gnmi.gNMI', 'Capabilities'): CapabilityRequest.FromString,
+      ('gnmi.gNMI', 'Get'): GetRequest.FromString,
+      ('gnmi.gNMI', 'Set'): SetRequest.FromString,
+      ('gnmi.gNMI', 'Subscribe'): SubscribeRequest.FromString,
+    }
+    response_serializers = {
+      ('gnmi.gNMI', 'Capabilities'): CapabilityResponse.SerializeToString,
+      ('gnmi.gNMI', 'Get'): GetResponse.SerializeToString,
+      ('gnmi.gNMI', 'Set'): SetResponse.SerializeToString,
+      ('gnmi.gNMI', 'Subscribe'): SubscribeResponse.SerializeToString,
+    }
+    method_implementations = {
+      ('gnmi.gNMI', 'Capabilities'): face_utilities.unary_unary_inline(servicer.Capabilities),
+      ('gnmi.gNMI', 'Get'): face_utilities.unary_unary_inline(servicer.Get),
+      ('gnmi.gNMI', 'Set'): face_utilities.unary_unary_inline(servicer.Set),
+      ('gnmi.gNMI', 'Subscribe'): face_utilities.stream_stream_inline(servicer.Subscribe),
+    }
+    server_options = beta_implementations.server_options(request_deserializers=request_deserializers, response_serializers=response_serializers, thread_pool=pool, thread_pool_size=pool_size, default_timeout=default_timeout, maximum_timeout=maximum_timeout)
+    return beta_implementations.server(method_implementations, options=server_options)
+
+
+  def beta_create_gNMI_stub(channel, host=None, metadata_transformer=None, pool=None, pool_size=None):
+    """The Beta API is deprecated for 0.15.0 and later.
+
+    It is recommended to use the GA API (classes and functions in this
+    file not marked beta) for all further purposes. This function was
+    generated only to ease transition from grpcio<0.15.0 to grpcio>=0.15.0"""
+    request_serializers = {
+      ('gnmi.gNMI', 'Capabilities'): CapabilityRequest.SerializeToString,
+      ('gnmi.gNMI', 'Get'): GetRequest.SerializeToString,
+      ('gnmi.gNMI', 'Set'): SetRequest.SerializeToString,
+      ('gnmi.gNMI', 'Subscribe'): SubscribeRequest.SerializeToString,
+    }
+    response_deserializers = {
+      ('gnmi.gNMI', 'Capabilities'): CapabilityResponse.FromString,
+      ('gnmi.gNMI', 'Get'): GetResponse.FromString,
+      ('gnmi.gNMI', 'Set'): SetResponse.FromString,
+      ('gnmi.gNMI', 'Subscribe'): SubscribeResponse.FromString,
+    }
+    cardinalities = {
+      'Capabilities': cardinality.Cardinality.UNARY_UNARY,
+      'Get': cardinality.Cardinality.UNARY_UNARY,
+      'Set': cardinality.Cardinality.UNARY_UNARY,
+      'Subscribe': cardinality.Cardinality.STREAM_STREAM,
+    }
+    stub_options = beta_implementations.stub_options(host=host, metadata_transformer=metadata_transformer, request_serializers=request_serializers, response_deserializers=response_deserializers, thread_pool=pool, thread_pool_size=pool_size)
+    return beta_implementations.dynamic_stub(channel, 'gnmi.gNMI', cardinalities, options=stub_options)
+except ImportError:
+  pass
+# @@protoc_insertion_point(module_scope)
diff --git a/src/telemetry/backend/collectors/gnmi_openconfig/gnmi/gnmi_pb2.pyi b/src/telemetry/backend/collectors/gnmi_openconfig/gnmi/gnmi_pb2.pyi
new file mode 100644
index 0000000000000000000000000000000000000000..423bcfb90e1a603c2ebcdc29092569c7695db2d0
--- /dev/null
+++ b/src/telemetry/backend/collectors/gnmi_openconfig/gnmi/gnmi_pb2.pyi
@@ -0,0 +1,380 @@
+from google.protobuf import any_pb2 as _any_pb2
+from google.protobuf import descriptor_pb2 as _descriptor_pb2
+from google.protobuf.internal import containers as _containers
+from google.protobuf.internal import enum_type_wrapper as _enum_type_wrapper
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import message as _message
+from typing import ClassVar as _ClassVar, Iterable as _Iterable, Mapping as _Mapping, Optional as _Optional, Union as _Union
+
+ASCII: Encoding
+BYTES: Encoding
+DESCRIPTOR: _descriptor.FileDescriptor
+EID_EXPERIMENTAL: ExtensionID
+EID_UNSET: ExtensionID
+GNMI_SERVICE_FIELD_NUMBER: _ClassVar[int]
+JSON: Encoding
+JSON_IETF: Encoding
+ON_CHANGE: SubscriptionMode
+PROTO: Encoding
+SAMPLE: SubscriptionMode
+TARGET_DEFINED: SubscriptionMode
+gnmi_service: _descriptor.FieldDescriptor
+
+class CapabilityRequest(_message.Message):
+    __slots__ = ["extension"]
+    EXTENSION_FIELD_NUMBER: _ClassVar[int]
+    extension: _containers.RepeatedCompositeFieldContainer[Extension]
+    def __init__(self, extension: _Optional[_Iterable[_Union[Extension, _Mapping]]] = ...) -> None: ...
+
+class CapabilityResponse(_message.Message):
+    __slots__ = ["extension", "gNMI_version", "supported_encodings", "supported_models"]
+    EXTENSION_FIELD_NUMBER: _ClassVar[int]
+    GNMI_VERSION_FIELD_NUMBER: _ClassVar[int]
+    SUPPORTED_ENCODINGS_FIELD_NUMBER: _ClassVar[int]
+    SUPPORTED_MODELS_FIELD_NUMBER: _ClassVar[int]
+    extension: _containers.RepeatedCompositeFieldContainer[Extension]
+    gNMI_version: str
+    supported_encodings: _containers.RepeatedScalarFieldContainer[Encoding]
+    supported_models: _containers.RepeatedCompositeFieldContainer[ModelData]
+    def __init__(self, supported_models: _Optional[_Iterable[_Union[ModelData, _Mapping]]] = ..., supported_encodings: _Optional[_Iterable[_Union[Encoding, str]]] = ..., gNMI_version: _Optional[str] = ..., extension: _Optional[_Iterable[_Union[Extension, _Mapping]]] = ...) -> None: ...
+
+class Decimal64(_message.Message):
+    __slots__ = ["digits", "precision"]
+    DIGITS_FIELD_NUMBER: _ClassVar[int]
+    PRECISION_FIELD_NUMBER: _ClassVar[int]
+    digits: int
+    precision: int
+    def __init__(self, digits: _Optional[int] = ..., precision: _Optional[int] = ...) -> None: ...
+
+class Error(_message.Message):
+    __slots__ = ["code", "data", "message"]
+    CODE_FIELD_NUMBER: _ClassVar[int]
+    DATA_FIELD_NUMBER: _ClassVar[int]
+    MESSAGE_FIELD_NUMBER: _ClassVar[int]
+    code: int
+    data: _any_pb2.Any
+    message: str
+    def __init__(self, code: _Optional[int] = ..., message: _Optional[str] = ..., data: _Optional[_Union[_any_pb2.Any, _Mapping]] = ...) -> None: ...
+
+class Extension(_message.Message):
+    __slots__ = ["history", "master_arbitration", "registered_ext"]
+    HISTORY_FIELD_NUMBER: _ClassVar[int]
+    MASTER_ARBITRATION_FIELD_NUMBER: _ClassVar[int]
+    REGISTERED_EXT_FIELD_NUMBER: _ClassVar[int]
+    history: History
+    master_arbitration: MasterArbitration
+    registered_ext: RegisteredExtension
+    def __init__(self, registered_ext: _Optional[_Union[RegisteredExtension, _Mapping]] = ..., master_arbitration: _Optional[_Union[MasterArbitration, _Mapping]] = ..., history: _Optional[_Union[History, _Mapping]] = ...) -> None: ...
+
+class GetRequest(_message.Message):
+    __slots__ = ["encoding", "extension", "path", "prefix", "type", "use_models"]
+    class DataType(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
+        __slots__ = []
+    ALL: GetRequest.DataType
+    CONFIG: GetRequest.DataType
+    ENCODING_FIELD_NUMBER: _ClassVar[int]
+    EXTENSION_FIELD_NUMBER: _ClassVar[int]
+    OPERATIONAL: GetRequest.DataType
+    PATH_FIELD_NUMBER: _ClassVar[int]
+    PREFIX_FIELD_NUMBER: _ClassVar[int]
+    STATE: GetRequest.DataType
+    TYPE_FIELD_NUMBER: _ClassVar[int]
+    USE_MODELS_FIELD_NUMBER: _ClassVar[int]
+    encoding: Encoding
+    extension: _containers.RepeatedCompositeFieldContainer[Extension]
+    path: _containers.RepeatedCompositeFieldContainer[Path]
+    prefix: Path
+    type: GetRequest.DataType
+    use_models: _containers.RepeatedCompositeFieldContainer[ModelData]
+    def __init__(self, prefix: _Optional[_Union[Path, _Mapping]] = ..., path: _Optional[_Iterable[_Union[Path, _Mapping]]] = ..., type: _Optional[_Union[GetRequest.DataType, str]] = ..., encoding: _Optional[_Union[Encoding, str]] = ..., use_models: _Optional[_Iterable[_Union[ModelData, _Mapping]]] = ..., extension: _Optional[_Iterable[_Union[Extension, _Mapping]]] = ...) -> None: ...
+
+class GetResponse(_message.Message):
+    __slots__ = ["error", "extension", "notification"]
+    ERROR_FIELD_NUMBER: _ClassVar[int]
+    EXTENSION_FIELD_NUMBER: _ClassVar[int]
+    NOTIFICATION_FIELD_NUMBER: _ClassVar[int]
+    error: Error
+    extension: _containers.RepeatedCompositeFieldContainer[Extension]
+    notification: _containers.RepeatedCompositeFieldContainer[Notification]
+    def __init__(self, notification: _Optional[_Iterable[_Union[Notification, _Mapping]]] = ..., error: _Optional[_Union[Error, _Mapping]] = ..., extension: _Optional[_Iterable[_Union[Extension, _Mapping]]] = ...) -> None: ...
+
+class History(_message.Message):
+    __slots__ = ["range", "snapshot_time"]
+    RANGE_FIELD_NUMBER: _ClassVar[int]
+    SNAPSHOT_TIME_FIELD_NUMBER: _ClassVar[int]
+    range: TimeRange
+    snapshot_time: int
+    def __init__(self, snapshot_time: _Optional[int] = ..., range: _Optional[_Union[TimeRange, _Mapping]] = ...) -> None: ...
+
+class MasterArbitration(_message.Message):
+    __slots__ = ["election_id", "role"]
+    ELECTION_ID_FIELD_NUMBER: _ClassVar[int]
+    ROLE_FIELD_NUMBER: _ClassVar[int]
+    election_id: Uint128
+    role: Role
+    def __init__(self, role: _Optional[_Union[Role, _Mapping]] = ..., election_id: _Optional[_Union[Uint128, _Mapping]] = ...) -> None: ...
+
+class ModelData(_message.Message):
+    __slots__ = ["name", "organization", "version"]
+    NAME_FIELD_NUMBER: _ClassVar[int]
+    ORGANIZATION_FIELD_NUMBER: _ClassVar[int]
+    VERSION_FIELD_NUMBER: _ClassVar[int]
+    name: str
+    organization: str
+    version: str
+    def __init__(self, name: _Optional[str] = ..., organization: _Optional[str] = ..., version: _Optional[str] = ...) -> None: ...
+
+class Notification(_message.Message):
+    __slots__ = ["atomic", "delete", "prefix", "timestamp", "update"]
+    ATOMIC_FIELD_NUMBER: _ClassVar[int]
+    DELETE_FIELD_NUMBER: _ClassVar[int]
+    PREFIX_FIELD_NUMBER: _ClassVar[int]
+    TIMESTAMP_FIELD_NUMBER: _ClassVar[int]
+    UPDATE_FIELD_NUMBER: _ClassVar[int]
+    atomic: bool
+    delete: _containers.RepeatedCompositeFieldContainer[Path]
+    prefix: Path
+    timestamp: int
+    update: _containers.RepeatedCompositeFieldContainer[Update]
+    def __init__(self, timestamp: _Optional[int] = ..., prefix: _Optional[_Union[Path, _Mapping]] = ..., update: _Optional[_Iterable[_Union[Update, _Mapping]]] = ..., delete: _Optional[_Iterable[_Union[Path, _Mapping]]] = ..., atomic: bool = ...) -> None: ...
+
+class Path(_message.Message):
+    __slots__ = ["elem", "element", "origin", "target"]
+    ELEMENT_FIELD_NUMBER: _ClassVar[int]
+    ELEM_FIELD_NUMBER: _ClassVar[int]
+    ORIGIN_FIELD_NUMBER: _ClassVar[int]
+    TARGET_FIELD_NUMBER: _ClassVar[int]
+    elem: _containers.RepeatedCompositeFieldContainer[PathElem]
+    element: _containers.RepeatedScalarFieldContainer[str]
+    origin: str
+    target: str
+    def __init__(self, element: _Optional[_Iterable[str]] = ..., origin: _Optional[str] = ..., elem: _Optional[_Iterable[_Union[PathElem, _Mapping]]] = ..., target: _Optional[str] = ...) -> None: ...
+
+class PathElem(_message.Message):
+    __slots__ = ["key", "name"]
+    class KeyEntry(_message.Message):
+        __slots__ = ["key", "value"]
+        KEY_FIELD_NUMBER: _ClassVar[int]
+        VALUE_FIELD_NUMBER: _ClassVar[int]
+        key: str
+        value: str
+        def __init__(self, key: _Optional[str] = ..., value: _Optional[str] = ...) -> None: ...
+    KEY_FIELD_NUMBER: _ClassVar[int]
+    NAME_FIELD_NUMBER: _ClassVar[int]
+    key: _containers.ScalarMap[str, str]
+    name: str
+    def __init__(self, name: _Optional[str] = ..., key: _Optional[_Mapping[str, str]] = ...) -> None: ...
+
+class Poll(_message.Message):
+    __slots__ = []
+    def __init__(self) -> None: ...
+
+class QOSMarking(_message.Message):
+    __slots__ = ["marking"]
+    MARKING_FIELD_NUMBER: _ClassVar[int]
+    marking: int
+    def __init__(self, marking: _Optional[int] = ...) -> None: ...
+
+class RegisteredExtension(_message.Message):
+    __slots__ = ["id", "msg"]
+    ID_FIELD_NUMBER: _ClassVar[int]
+    MSG_FIELD_NUMBER: _ClassVar[int]
+    id: ExtensionID
+    msg: bytes
+    def __init__(self, id: _Optional[_Union[ExtensionID, str]] = ..., msg: _Optional[bytes] = ...) -> None: ...
+
+class Role(_message.Message):
+    __slots__ = ["id"]
+    ID_FIELD_NUMBER: _ClassVar[int]
+    id: str
+    def __init__(self, id: _Optional[str] = ...) -> None: ...
+
+class ScalarArray(_message.Message):
+    __slots__ = ["element"]
+    ELEMENT_FIELD_NUMBER: _ClassVar[int]
+    element: _containers.RepeatedCompositeFieldContainer[TypedValue]
+    def __init__(self, element: _Optional[_Iterable[_Union[TypedValue, _Mapping]]] = ...) -> None: ...
+
+class SetRequest(_message.Message):
+    __slots__ = ["delete", "extension", "prefix", "replace", "update"]
+    DELETE_FIELD_NUMBER: _ClassVar[int]
+    EXTENSION_FIELD_NUMBER: _ClassVar[int]
+    PREFIX_FIELD_NUMBER: _ClassVar[int]
+    REPLACE_FIELD_NUMBER: _ClassVar[int]
+    UPDATE_FIELD_NUMBER: _ClassVar[int]
+    delete: _containers.RepeatedCompositeFieldContainer[Path]
+    extension: _containers.RepeatedCompositeFieldContainer[Extension]
+    prefix: Path
+    replace: _containers.RepeatedCompositeFieldContainer[Update]
+    update: _containers.RepeatedCompositeFieldContainer[Update]
+    def __init__(self, prefix: _Optional[_Union[Path, _Mapping]] = ..., delete: _Optional[_Iterable[_Union[Path, _Mapping]]] = ..., replace: _Optional[_Iterable[_Union[Update, _Mapping]]] = ..., update: _Optional[_Iterable[_Union[Update, _Mapping]]] = ..., extension: _Optional[_Iterable[_Union[Extension, _Mapping]]] = ...) -> None: ...
+
+class SetResponse(_message.Message):
+    __slots__ = ["extension", "message", "prefix", "response", "timestamp"]
+    EXTENSION_FIELD_NUMBER: _ClassVar[int]
+    MESSAGE_FIELD_NUMBER: _ClassVar[int]
+    PREFIX_FIELD_NUMBER: _ClassVar[int]
+    RESPONSE_FIELD_NUMBER: _ClassVar[int]
+    TIMESTAMP_FIELD_NUMBER: _ClassVar[int]
+    extension: _containers.RepeatedCompositeFieldContainer[Extension]
+    message: Error
+    prefix: Path
+    response: _containers.RepeatedCompositeFieldContainer[UpdateResult]
+    timestamp: int
+    def __init__(self, prefix: _Optional[_Union[Path, _Mapping]] = ..., response: _Optional[_Iterable[_Union[UpdateResult, _Mapping]]] = ..., message: _Optional[_Union[Error, _Mapping]] = ..., timestamp: _Optional[int] = ..., extension: _Optional[_Iterable[_Union[Extension, _Mapping]]] = ...) -> None: ...
+
+class SubscribeRequest(_message.Message):
+    __slots__ = ["extension", "poll", "subscribe"]
+    EXTENSION_FIELD_NUMBER: _ClassVar[int]
+    POLL_FIELD_NUMBER: _ClassVar[int]
+    SUBSCRIBE_FIELD_NUMBER: _ClassVar[int]
+    extension: _containers.RepeatedCompositeFieldContainer[Extension]
+    poll: Poll
+    subscribe: SubscriptionList
+    def __init__(self, subscribe: _Optional[_Union[SubscriptionList, _Mapping]] = ..., poll: _Optional[_Union[Poll, _Mapping]] = ..., extension: _Optional[_Iterable[_Union[Extension, _Mapping]]] = ...) -> None: ...
+
+class SubscribeResponse(_message.Message):
+    __slots__ = ["error", "extension", "sync_response", "update"]
+    ERROR_FIELD_NUMBER: _ClassVar[int]
+    EXTENSION_FIELD_NUMBER: _ClassVar[int]
+    SYNC_RESPONSE_FIELD_NUMBER: _ClassVar[int]
+    UPDATE_FIELD_NUMBER: _ClassVar[int]
+    error: Error
+    extension: _containers.RepeatedCompositeFieldContainer[Extension]
+    sync_response: bool
+    update: Notification
+    def __init__(self, update: _Optional[_Union[Notification, _Mapping]] = ..., sync_response: bool = ..., error: _Optional[_Union[Error, _Mapping]] = ..., extension: _Optional[_Iterable[_Union[Extension, _Mapping]]] = ...) -> None: ...
+
+class Subscription(_message.Message):
+    __slots__ = ["heartbeat_interval", "mode", "path", "sample_interval", "suppress_redundant"]
+    HEARTBEAT_INTERVAL_FIELD_NUMBER: _ClassVar[int]
+    MODE_FIELD_NUMBER: _ClassVar[int]
+    PATH_FIELD_NUMBER: _ClassVar[int]
+    SAMPLE_INTERVAL_FIELD_NUMBER: _ClassVar[int]
+    SUPPRESS_REDUNDANT_FIELD_NUMBER: _ClassVar[int]
+    heartbeat_interval: int
+    mode: SubscriptionMode
+    path: Path
+    sample_interval: int
+    suppress_redundant: bool
+    def __init__(self, path: _Optional[_Union[Path, _Mapping]] = ..., mode: _Optional[_Union[SubscriptionMode, str]] = ..., sample_interval: _Optional[int] = ..., suppress_redundant: bool = ..., heartbeat_interval: _Optional[int] = ...) -> None: ...
+
+class SubscriptionList(_message.Message):
+    __slots__ = ["allow_aggregation", "encoding", "mode", "prefix", "qos", "subscription", "updates_only", "use_models"]
+    class Mode(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
+        __slots__ = []
+    ALLOW_AGGREGATION_FIELD_NUMBER: _ClassVar[int]
+    ENCODING_FIELD_NUMBER: _ClassVar[int]
+    MODE_FIELD_NUMBER: _ClassVar[int]
+    ONCE: SubscriptionList.Mode
+    POLL: SubscriptionList.Mode
+    PREFIX_FIELD_NUMBER: _ClassVar[int]
+    QOS_FIELD_NUMBER: _ClassVar[int]
+    STREAM: SubscriptionList.Mode
+    SUBSCRIPTION_FIELD_NUMBER: _ClassVar[int]
+    UPDATES_ONLY_FIELD_NUMBER: _ClassVar[int]
+    USE_MODELS_FIELD_NUMBER: _ClassVar[int]
+    allow_aggregation: bool
+    encoding: Encoding
+    mode: SubscriptionList.Mode
+    prefix: Path
+    qos: QOSMarking
+    subscription: _containers.RepeatedCompositeFieldContainer[Subscription]
+    updates_only: bool
+    use_models: _containers.RepeatedCompositeFieldContainer[ModelData]
+    def __init__(self, prefix: _Optional[_Union[Path, _Mapping]] = ..., subscription: _Optional[_Iterable[_Union[Subscription, _Mapping]]] = ..., qos: _Optional[_Union[QOSMarking, _Mapping]] = ..., mode: _Optional[_Union[SubscriptionList.Mode, str]] = ..., allow_aggregation: bool = ..., use_models: _Optional[_Iterable[_Union[ModelData, _Mapping]]] = ..., encoding: _Optional[_Union[Encoding, str]] = ..., updates_only: bool = ...) -> None: ...
+
+class TimeRange(_message.Message):
+    __slots__ = ["end", "start"]
+    END_FIELD_NUMBER: _ClassVar[int]
+    START_FIELD_NUMBER: _ClassVar[int]
+    end: int
+    start: int
+    def __init__(self, start: _Optional[int] = ..., end: _Optional[int] = ...) -> None: ...
+
+class TypedValue(_message.Message):
+    __slots__ = ["any_val", "ascii_val", "bool_val", "bytes_val", "decimal_val", "double_val", "float_val", "int_val", "json_ietf_val", "json_val", "leaflist_val", "proto_bytes", "string_val", "uint_val"]
+    ANY_VAL_FIELD_NUMBER: _ClassVar[int]
+    ASCII_VAL_FIELD_NUMBER: _ClassVar[int]
+    BOOL_VAL_FIELD_NUMBER: _ClassVar[int]
+    BYTES_VAL_FIELD_NUMBER: _ClassVar[int]
+    DECIMAL_VAL_FIELD_NUMBER: _ClassVar[int]
+    DOUBLE_VAL_FIELD_NUMBER: _ClassVar[int]
+    FLOAT_VAL_FIELD_NUMBER: _ClassVar[int]
+    INT_VAL_FIELD_NUMBER: _ClassVar[int]
+    JSON_IETF_VAL_FIELD_NUMBER: _ClassVar[int]
+    JSON_VAL_FIELD_NUMBER: _ClassVar[int]
+    LEAFLIST_VAL_FIELD_NUMBER: _ClassVar[int]
+    PROTO_BYTES_FIELD_NUMBER: _ClassVar[int]
+    STRING_VAL_FIELD_NUMBER: _ClassVar[int]
+    UINT_VAL_FIELD_NUMBER: _ClassVar[int]
+    any_val: _any_pb2.Any
+    ascii_val: str
+    bool_val: bool
+    bytes_val: bytes
+    decimal_val: Decimal64
+    double_val: float
+    float_val: float
+    int_val: int
+    json_ietf_val: bytes
+    json_val: bytes
+    leaflist_val: ScalarArray
+    proto_bytes: bytes
+    string_val: str
+    uint_val: int
+    def __init__(self, string_val: _Optional[str] = ..., int_val: _Optional[int] = ..., uint_val: _Optional[int] = ..., bool_val: bool = ..., bytes_val: _Optional[bytes] = ..., float_val: _Optional[float] = ..., double_val: _Optional[float] = ..., decimal_val: _Optional[_Union[Decimal64, _Mapping]] = ..., leaflist_val: _Optional[_Union[ScalarArray, _Mapping]] = ..., any_val: _Optional[_Union[_any_pb2.Any, _Mapping]] = ..., json_val: _Optional[bytes] = ..., json_ietf_val: _Optional[bytes] = ..., ascii_val: _Optional[str] = ..., proto_bytes: _Optional[bytes] = ...) -> None: ...
+
+class Uint128(_message.Message):
+    __slots__ = ["high", "low"]
+    HIGH_FIELD_NUMBER: _ClassVar[int]
+    LOW_FIELD_NUMBER: _ClassVar[int]
+    high: int
+    low: int
+    def __init__(self, high: _Optional[int] = ..., low: _Optional[int] = ...) -> None: ...
+
+class Update(_message.Message):
+    __slots__ = ["duplicates", "path", "val", "value"]
+    DUPLICATES_FIELD_NUMBER: _ClassVar[int]
+    PATH_FIELD_NUMBER: _ClassVar[int]
+    VALUE_FIELD_NUMBER: _ClassVar[int]
+    VAL_FIELD_NUMBER: _ClassVar[int]
+    duplicates: int
+    path: Path
+    val: TypedValue
+    value: Value
+    def __init__(self, path: _Optional[_Union[Path, _Mapping]] = ..., value: _Optional[_Union[Value, _Mapping]] = ..., val: _Optional[_Union[TypedValue, _Mapping]] = ..., duplicates: _Optional[int] = ...) -> None: ...
+
+class UpdateResult(_message.Message):
+    __slots__ = ["message", "op", "path", "timestamp"]
+    class Operation(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
+        __slots__ = []
+    DELETE: UpdateResult.Operation
+    INVALID: UpdateResult.Operation
+    MESSAGE_FIELD_NUMBER: _ClassVar[int]
+    OP_FIELD_NUMBER: _ClassVar[int]
+    PATH_FIELD_NUMBER: _ClassVar[int]
+    REPLACE: UpdateResult.Operation
+    TIMESTAMP_FIELD_NUMBER: _ClassVar[int]
+    UPDATE: UpdateResult.Operation
+    message: Error
+    op: UpdateResult.Operation
+    path: Path
+    timestamp: int
+    def __init__(self, timestamp: _Optional[int] = ..., path: _Optional[_Union[Path, _Mapping]] = ..., message: _Optional[_Union[Error, _Mapping]] = ..., op: _Optional[_Union[UpdateResult.Operation, str]] = ...) -> None: ...
+
+class Value(_message.Message):
+    __slots__ = ["type", "value"]
+    TYPE_FIELD_NUMBER: _ClassVar[int]
+    VALUE_FIELD_NUMBER: _ClassVar[int]
+    type: Encoding
+    value: bytes
+    def __init__(self, value: _Optional[bytes] = ..., type: _Optional[_Union[Encoding, str]] = ...) -> None: ...
+
+class ExtensionID(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
+    __slots__ = []
+
+class Encoding(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
+    __slots__ = []
+
+class SubscriptionMode(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
+    __slots__ = []
\ No newline at end of file
diff --git a/src/telemetry/backend/collectors/gnmi_openconfig/gnmi/gnmi_pb2_grpc.py b/src/telemetry/backend/collectors/gnmi_openconfig/gnmi/gnmi_pb2_grpc.py
new file mode 100644
index 0000000000000000000000000000000000000000..517d3d9eb41c5833a28cc9b7f43859dde186f348
--- /dev/null
+++ b/src/telemetry/backend/collectors/gnmi_openconfig/gnmi/gnmi_pb2_grpc.py
@@ -0,0 +1,185 @@
+# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
+"""Client and server classes corresponding to protobuf-defined services."""
+import grpc
+
+from . import gnmi_pb2 as gnmi__pb2
+
+
+class gNMIStub(object):
+    """Missing associated documentation comment in .proto file."""
+
+    def __init__(self, channel):
+        """Constructor.
+
+        Args:
+            channel: A grpc.Channel.
+        """
+        self.Capabilities = channel.unary_unary(
+                '/gnmi.gNMI/Capabilities',
+                request_serializer=gnmi__pb2.CapabilityRequest.SerializeToString,
+                response_deserializer=gnmi__pb2.CapabilityResponse.FromString,
+                )
+        self.Get = channel.unary_unary(
+                '/gnmi.gNMI/Get',
+                request_serializer=gnmi__pb2.GetRequest.SerializeToString,
+                response_deserializer=gnmi__pb2.GetResponse.FromString,
+                )
+        self.Set = channel.unary_unary(
+                '/gnmi.gNMI/Set',
+                request_serializer=gnmi__pb2.SetRequest.SerializeToString,
+                response_deserializer=gnmi__pb2.SetResponse.FromString,
+                )
+        self.Subscribe = channel.stream_stream(
+                '/gnmi.gNMI/Subscribe',
+                request_serializer=gnmi__pb2.SubscribeRequest.SerializeToString,
+                response_deserializer=gnmi__pb2.SubscribeResponse.FromString,
+                )
+
+
+class gNMIServicer(object):
+    """Missing associated documentation comment in .proto file."""
+
+    def Capabilities(self, request, context):
+        """Capabilities allows the client to retrieve the set of capabilities that
+        is supported by the target. This allows the target to validate the
+        service version that is implemented and retrieve the set of models that
+        the target supports. The models can then be specified in subsequent RPCs
+        to restrict the set of data that is utilized.
+        Reference: gNMI Specification Section 3.2
+        """
+        context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+        context.set_details('Method not implemented!')
+        raise NotImplementedError('Method not implemented!')
+
+    def Get(self, request, context):
+        """Retrieve a snapshot of data from the target. A Get RPC requests that the
+        target snapshots a subset of the data tree as specified by the paths
+        included in the message and serializes this to be returned to the
+        client using the specified encoding.
+        Reference: gNMI Specification Section 3.3
+        """
+        context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+        context.set_details('Method not implemented!')
+        raise NotImplementedError('Method not implemented!')
+
+    def Set(self, request, context):
+        """Set allows the client to modify the state of data on the target. The
+        paths to modified along with the new values that the client wishes
+        to set the value to.
+        Reference: gNMI Specification Section 3.4
+        """
+        context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+        context.set_details('Method not implemented!')
+        raise NotImplementedError('Method not implemented!')
+
+    def Subscribe(self, request_iterator, context):
+        """Subscribe allows a client to request the target to send it values
+        of particular paths within the data tree. These values may be streamed
+        at a particular cadence (STREAM), sent one off on a long-lived channel
+        (POLL), or sent as a one-off retrieval (ONCE).
+        Reference: gNMI Specification Section 3.5
+        """
+        context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+        context.set_details('Method not implemented!')
+        raise NotImplementedError('Method not implemented!')
+
+
+def add_gNMIServicer_to_server(servicer, server):
+    rpc_method_handlers = {
+            'Capabilities': grpc.unary_unary_rpc_method_handler(
+                    servicer.Capabilities,
+                    request_deserializer=gnmi__pb2.CapabilityRequest.FromString,
+                    response_serializer=gnmi__pb2.CapabilityResponse.SerializeToString,
+            ),
+            'Get': grpc.unary_unary_rpc_method_handler(
+                    servicer.Get,
+                    request_deserializer=gnmi__pb2.GetRequest.FromString,
+                    response_serializer=gnmi__pb2.GetResponse.SerializeToString,
+            ),
+            'Set': grpc.unary_unary_rpc_method_handler(
+                    servicer.Set,
+                    request_deserializer=gnmi__pb2.SetRequest.FromString,
+                    response_serializer=gnmi__pb2.SetResponse.SerializeToString,
+            ),
+            'Subscribe': grpc.stream_stream_rpc_method_handler(
+                    servicer.Subscribe,
+                    request_deserializer=gnmi__pb2.SubscribeRequest.FromString,
+                    response_serializer=gnmi__pb2.SubscribeResponse.SerializeToString,
+            ),
+    }
+    generic_handler = grpc.method_handlers_generic_handler(
+            'gnmi.gNMI', rpc_method_handlers)
+    server.add_generic_rpc_handlers((generic_handler,))
+
+
+ # This class is part of an EXPERIMENTAL API.
+class gNMI(object):
+    """Missing associated documentation comment in .proto file."""
+
+    @staticmethod
+    def Capabilities(request,
+            target,
+            options=(),
+            channel_credentials=None,
+            call_credentials=None,
+            insecure=False,
+            compression=None,
+            wait_for_ready=None,
+            timeout=None,
+            metadata=None):
+        return grpc.experimental.unary_unary(request, target, '/gnmi.gNMI/Capabilities',
+            gnmi__pb2.CapabilityRequest.SerializeToString,
+            gnmi__pb2.CapabilityResponse.FromString,
+            options, channel_credentials,
+            insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
+
+    @staticmethod
+    def Get(request,
+            target,
+            options=(),
+            channel_credentials=None,
+            call_credentials=None,
+            insecure=False,
+            compression=None,
+            wait_for_ready=None,
+            timeout=None,
+            metadata=None):
+        return grpc.experimental.unary_unary(request, target, '/gnmi.gNMI/Get',
+            gnmi__pb2.GetRequest.SerializeToString,
+            gnmi__pb2.GetResponse.FromString,
+            options, channel_credentials,
+            insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
+
+    @staticmethod
+    def Set(request,
+            target,
+            options=(),
+            channel_credentials=None,
+            call_credentials=None,
+            insecure=False,
+            compression=None,
+            wait_for_ready=None,
+            timeout=None,
+            metadata=None):
+        return grpc.experimental.unary_unary(request, target, '/gnmi.gNMI/Set',
+            gnmi__pb2.SetRequest.SerializeToString,
+            gnmi__pb2.SetResponse.FromString,
+            options, channel_credentials,
+            insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
+
+    @staticmethod
+    def Subscribe(request_iterator,
+            target,
+            options=(),
+            channel_credentials=None,
+            call_credentials=None,
+            insecure=False,
+            compression=None,
+            wait_for_ready=None,
+            timeout=None,
+            metadata=None):
+        return grpc.experimental.stream_stream(request_iterator, target, '/gnmi.gNMI/Subscribe',
+            gnmi__pb2.SubscribeRequest.SerializeToString,
+            gnmi__pb2.SubscribeResponse.FromString,
+            options, channel_credentials,
+            insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
diff --git a/src/telemetry/backend/collectors/gnmi_openconfig/handlers/Component.py b/src/telemetry/backend/collectors/gnmi_openconfig/handlers/Component.py
new file mode 100644
index 0000000000000000000000000000000000000000..3cad5f5f2bed6f2c496a35a16130df42e41ad71b
--- /dev/null
+++ b/src/telemetry/backend/collectors/gnmi_openconfig/handlers/Component.py
@@ -0,0 +1,70 @@
+# Copyright 2022-2024 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/)
+#
+# 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.
+
+import json, logging, re # libyang
+from typing import Any, Dict, List, Tuple
+from common.proto.kpi_sample_types_pb2 import KpiSampleType
+from ._Handler import _Handler
+from .YangHandler import YangHandler
+
+LOGGER = logging.getLogger(__name__)
+
+PATH_IF_CTR = '/openconfig-interfaces:interfaces/interface[name={:s}]/state/counters/{:s}'
+
+#pylint: disable=abstract-method
+class ComponentHandler(_Handler):
+    def get_resource_key(self) -> str: return '/endpoints/endpoint'
+    def get_path(self) -> str: return '/openconfig-platform:components'
+
+    def parse(
+        self, json_data : Dict, yang_handler : YangHandler
+    ) -> List[Tuple[str, Dict[str, Any]]]:
+        LOGGER.debug('json_data = {:s}'.format(json.dumps(json_data)))
+
+        yang_components_path = self.get_path()
+        json_data_valid = yang_handler.parse_to_dict(yang_components_path, json_data, fmt='json')
+
+        entries = []
+        for component in json_data_valid['components']['component']:
+            LOGGER.debug('component={:s}'.format(str(component)))
+
+            component_name = component['name']
+            #component_config = component.get('config', {})
+
+            #yang_components : libyang.DContainer = yang_handler.get_data_path(yang_components_path)
+            #yang_component_path = 'component[name="{:s}"]'.format(component_name)
+            #yang_component : libyang.DContainer = yang_components.create_path(yang_component_path)
+            #yang_component.merge_data_dict(component, strict=True, validate=False)
+
+            component_state = component.get('state', {})
+            component_type = component_state.get('type')
+            if component_type is None: continue
+            component_type = component_type.split(':')[-1]
+            if component_type not in {'PORT'}: continue
+
+            # TODO: improve mapping between interface name and component name
+            # By now, computed by time for the sake of saving time for the Hackfest.
+            interface_name = re.sub(r'\-[pP][oO][rR][tT]', '', component_name)
+
+            endpoint = {'uuid': interface_name, 'type': '-'}
+            endpoint['sample_types'] = {
+                KpiSampleType.KPISAMPLETYPE_BYTES_RECEIVED     : PATH_IF_CTR.format(interface_name, 'in-octets' ),
+                KpiSampleType.KPISAMPLETYPE_BYTES_TRANSMITTED  : PATH_IF_CTR.format(interface_name, 'out-octets'),
+                KpiSampleType.KPISAMPLETYPE_PACKETS_RECEIVED   : PATH_IF_CTR.format(interface_name, 'in-pkts'   ),
+                KpiSampleType.KPISAMPLETYPE_PACKETS_TRANSMITTED: PATH_IF_CTR.format(interface_name, 'out-pkts'  ),
+            }
+
+            entries.append(('/endpoints/endpoint[{:s}]'.format(endpoint['uuid']), endpoint))
+
+        return entries
diff --git a/src/telemetry/backend/collectors/gnmi_openconfig/handlers/Interface.py b/src/telemetry/backend/collectors/gnmi_openconfig/handlers/Interface.py
new file mode 100644
index 0000000000000000000000000000000000000000..ed833b647d9c856cd7e54c5258b14924d187eb9f
--- /dev/null
+++ b/src/telemetry/backend/collectors/gnmi_openconfig/handlers/Interface.py
@@ -0,0 +1,208 @@
+# Copyright 2022-2024 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/)
+#
+# 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.
+
+import json, libyang, logging
+from typing import Any, Dict, List, Tuple
+from ._Handler import _Handler
+from .Tools import get_bool, get_int, get_str
+from .YangHandler import YangHandler
+
+LOGGER = logging.getLogger(__name__)
+
+class InterfaceHandler(_Handler):
+    def get_resource_key(self) -> str: return '/interface/subinterface'
+    def get_path(self) -> str: return '/openconfig-interfaces:interfaces'
+
+    def compose(
+        self, resource_key : str, resource_value : Dict, yang_handler : YangHandler, delete : bool = False
+    ) -> Tuple[str, str]:
+        if_name   = get_str(resource_value, 'name'    )  # ethernet-1/1
+        sif_index = get_int(resource_value, 'index', 0)  # 0
+
+        if delete:
+            PATH_TMPL = '/interfaces/interface[name={:s}]/subinterfaces/subinterface[index={:d}]'
+            str_path = PATH_TMPL.format(if_name, sif_index)
+            str_data = json.dumps({})
+
+            root_node : libyang.DContainer = yang_handler.get_data_path(
+                '/openconfig-interfaces:interfaces'
+            )
+            yang_sif = root_node.find_path('/'.join([
+                '', # add slash at the beginning
+                'openconfig-interfaces:interfaces',
+                'interface[name="{:s}"]'.format(if_name),
+                'subinterfaces',
+                'subinterface[index="{:d}"]'.format(sif_index),
+            ]))
+            if yang_sif is not None:
+                yang_sif.unlink()
+                yang_sif.free()
+
+            return str_path, str_data
+
+        enabled        = get_bool(resource_value, 'enabled',  True) # True/False
+        #if_type        = get_str (resource_value, 'type'         ) # 'l3ipvlan'
+        vlan_id        = get_int (resource_value, 'vlan_id',      ) # 127
+        address_ip     = get_str (resource_value, 'address_ip'    ) # 172.16.0.1
+        address_prefix = get_int (resource_value, 'address_prefix') # 24
+        mtu            = get_int (resource_value, 'mtu'           ) # 1500
+
+        yang_ifs : libyang.DContainer = yang_handler.get_data_path('/openconfig-interfaces:interfaces')
+        yang_if_path = 'interface[name="{:s}"]'.format(if_name)
+        yang_if : libyang.DContainer = yang_ifs.create_path(yang_if_path)
+        yang_if.create_path('config/name',    if_name   )
+        if enabled is not None: yang_if.create_path('config/enabled', enabled)
+        if mtu     is not None: yang_if.create_path('config/mtu',     mtu)
+
+        yang_sifs : libyang.DContainer = yang_if.create_path('subinterfaces')
+        yang_sif_path = 'subinterface[index="{:d}"]'.format(sif_index)
+        yang_sif : libyang.DContainer = yang_sifs.create_path(yang_sif_path)
+        yang_sif.create_path('config/index', sif_index)
+        if enabled is not None: yang_sif.create_path('config/enabled', enabled)
+
+        if vlan_id is not None:
+            yang_subif_vlan : libyang.DContainer = yang_sif.create_path('openconfig-vlan:vlan')
+            yang_subif_vlan.create_path('match/single-tagged/config/vlan-id', vlan_id)
+
+        yang_ipv4 : libyang.DContainer = yang_sif.create_path('openconfig-if-ip:ipv4')
+        if enabled is not None: yang_ipv4.create_path('config/enabled', enabled)
+
+        if address_ip is not None and address_prefix is not None:
+            yang_ipv4_addrs : libyang.DContainer = yang_ipv4.create_path('addresses')
+            yang_ipv4_addr_path = 'address[ip="{:s}"]'.format(address_ip)
+            yang_ipv4_addr : libyang.DContainer = yang_ipv4_addrs.create_path(yang_ipv4_addr_path)
+            yang_ipv4_addr.create_path('config/ip',            address_ip)
+            yang_ipv4_addr.create_path('config/prefix-length', address_prefix)
+
+        str_path = '/interfaces/interface[name={:s}]'.format(if_name)
+        str_data = yang_if.print_mem('json')
+        json_data = json.loads(str_data)
+        json_data = json_data['openconfig-interfaces:interface'][0]
+        str_data = json.dumps(json_data)
+        return str_path, str_data
+
+    def parse(
+        self, json_data : Dict, yang_handler : YangHandler
+    ) -> List[Tuple[str, Dict[str, Any]]]:
+        LOGGER.debug('json_data = {:s}'.format(json.dumps(json_data)))
+
+        yang_interfaces_path = self.get_path()
+        json_data_valid = yang_handler.parse_to_dict(yang_interfaces_path, json_data, fmt='json')
+
+        entries = []
+        for interface in json_data_valid['interfaces']['interface']:
+            LOGGER.debug('interface={:s}'.format(str(interface)))
+
+            interface_name = interface['name']
+            interface_config = interface.get('config', {})
+
+            #yang_interfaces : libyang.DContainer = yang_handler.get_data_path(yang_interfaces_path)
+            #yang_interface_path = 'interface[name="{:s}"]'.format(interface_name)
+            #yang_interface : libyang.DContainer = yang_interfaces.create_path(yang_interface_path)
+            #yang_interface.merge_data_dict(interface, strict=True, validate=False)
+
+            interface_state = interface.get('state', {})
+            interface_type = interface_state.get('type')
+            if interface_type is None: continue
+            interface_type = interface_type.split(':')[-1]
+            if interface_type not in {'ethernetCsmacd'}: continue
+
+            _interface = {
+                'name'         : interface_name,
+                'type'         : interface_type,
+                'mtu'          : interface_state['mtu'],
+                'admin-status' : interface_state['admin-status'],
+                'oper-status'  : interface_state['oper-status'],
+                'management'   : interface_state['management'],
+            }
+            if not interface_state['management'] and 'ifindex' in interface_state:
+                _interface['ifindex'] = interface_state['ifindex']
+            if 'description' in interface_config:
+                _interface['description'] = interface_config['description']
+            if 'enabled' in interface_config:
+                _interface['enabled'] = interface_config['enabled']
+            if 'hardware-port' in interface_state:
+                _interface['hardware-port'] = interface_state['hardware-port']
+            if 'transceiver' in interface_state:
+                _interface['transceiver'] = interface_state['transceiver']
+
+            entry_interface_key = '/interface[{:s}]'.format(interface_name)
+            entries.append((entry_interface_key, _interface))
+
+            if interface_type == 'ethernetCsmacd':
+                ethernet_state = interface['ethernet']['state']
+
+                _ethernet = {
+                    'mac-address'           : ethernet_state['mac-address'],
+                    'hw-mac-address'        : ethernet_state['hw-mac-address'],
+                    'port-speed'            : ethernet_state['port-speed'].split(':')[-1],
+                    'negotiated-port-speed' : ethernet_state['negotiated-port-speed'].split(':')[-1],
+                }
+                entry_ethernet_key = '{:s}/ethernet'.format(entry_interface_key)
+                entries.append((entry_ethernet_key, _ethernet))
+
+            subinterfaces = interface.get('subinterfaces', {}).get('subinterface', [])
+            for subinterface in subinterfaces:
+                LOGGER.debug('subinterface={:s}'.format(str(subinterface)))
+
+                subinterface_index = subinterface['index']
+                subinterface_state = subinterface.get('state', {})
+
+                _subinterface = {'index': subinterface_index}
+                if 'name' in subinterface_state:
+                    _subinterface['name'] = subinterface_state['name']
+                if 'enabled' in subinterface_state:
+                    _subinterface['enabled'] = subinterface_state['enabled']
+
+                if 'vlan' in subinterface:
+                    vlan = subinterface['vlan']
+                    vlan_match = vlan['match']
+
+                    single_tagged = vlan_match.pop('single-tagged', None)
+                    if single_tagged is not None:
+                        single_tagged_config = single_tagged['config']
+                        vlan_id = single_tagged_config['vlan-id']
+                        _subinterface['vlan_id'] = vlan_id
+
+                    if len(vlan_match) > 0:
+                        raise Exception('Unsupported VLAN schema: {:s}'.format(str(vlan)))
+
+                ipv4_addresses = subinterface.get('ipv4', {}).get('addresses', {}).get('address', [])
+                if len(ipv4_addresses) > 1:
+                    raise Exception('Multiple IPv4 Addresses not supported: {:s}'.format(str(ipv4_addresses)))
+                for ipv4_address in ipv4_addresses:
+                    LOGGER.debug('ipv4_address={:s}'.format(str(ipv4_address)))
+                    _subinterface['address_ip'] = ipv4_address['ip']
+                    ipv4_address_state = ipv4_address.get('state', {})
+                    #if 'origin' in ipv4_address_state:
+                    #    _subinterface['origin'] = ipv4_address_state['origin']
+                    if 'prefix-length' in ipv4_address_state:
+                        _subinterface['address_prefix'] = ipv4_address_state['prefix-length']
+
+                ipv6_addresses = subinterface.get('ipv6', {}).get('addresses', {}).get('address', [])
+                if len(ipv6_addresses) > 1:
+                    raise Exception('Multiple IPv6 Addresses not supported: {:s}'.format(str(ipv6_addresses)))
+                for ipv6_address in ipv6_addresses:
+                    LOGGER.debug('ipv6_address={:s}'.format(str(ipv6_address)))
+                    _subinterface['address_ipv6'] = ipv6_address['ip']
+                    ipv6_address_state = ipv6_address.get('state', {})
+                    #if 'origin' in ipv6_address_state:
+                    #    _subinterface['origin_ipv6'] = ipv6_address_state['origin']
+                    if 'prefix-length' in ipv6_address_state:
+                        _subinterface['address_prefix_ipv6'] = ipv6_address_state['prefix-length']
+
+                entry_subinterface_key = '{:s}/subinterface[{:d}]'.format(entry_interface_key, subinterface_index)
+                entries.append((entry_subinterface_key, _subinterface))
+
+        return entries
diff --git a/src/telemetry/backend/collectors/gnmi_openconfig/handlers/InterfaceCounter.py b/src/telemetry/backend/collectors/gnmi_openconfig/handlers/InterfaceCounter.py
new file mode 100644
index 0000000000000000000000000000000000000000..c72a4ea3af5dd7f1ee71560dcad37a06b7d2fb32
--- /dev/null
+++ b/src/telemetry/backend/collectors/gnmi_openconfig/handlers/InterfaceCounter.py
@@ -0,0 +1,64 @@
+# Copyright 2022-2024 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/)
+#
+# 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.
+
+import json, libyang, logging
+from typing import Any, Dict, List, Tuple
+from ._Handler import _Handler
+from .YangHandler import YangHandler
+
+LOGGER = logging.getLogger(__name__)
+
+#pylint: disable=abstract-method
+class InterfaceCounterHandler(_Handler):
+    def get_resource_key(self) -> str: return '/interface/counters'
+    def get_path(self) -> str: return '/openconfig-interfaces:interfaces/interface/state/counters'
+
+    def parse(
+        self, json_data : Dict, yang_handler : YangHandler
+    ) -> List[Tuple[str, Dict[str, Any]]]:
+        LOGGER.debug('json_data = {:s}'.format(json.dumps(json_data)))
+
+        yang_interfaces_path = self.get_path()
+        json_data_valid = yang_handler.parse_to_dict(yang_interfaces_path, json_data, fmt='json')
+
+        entries = []
+        for interface in json_data_valid['interfaces']['interface']:
+            LOGGER.debug('interface={:s}'.format(str(interface)))
+
+            interface_name = interface['name']
+            interface_counters = interface.get('state', {}).get('counters', {})
+            _interface = {
+                'name'              : interface_name,
+                'in-broadcast-pkts' : interface_counters['in_broadcast_pkts' ],
+                'in-discards'       : interface_counters['in_discards'       ],
+                'in-errors'         : interface_counters['in_errors'         ],
+                'in-fcs-errors'     : interface_counters['in_fcs_errors'     ],
+                'in-multicast-pkts' : interface_counters['in_multicast_pkts' ],
+                'in-octets'         : interface_counters['in_octets'         ],
+                'in-pkts'           : interface_counters['in_pkts'           ],
+                'in-unicast-pkts'   : interface_counters['in_unicast_pkts'   ],
+                'out-broadcast-pkts': interface_counters['out_broadcast_pkts'],
+                'out-discards'      : interface_counters['out_discards'      ],
+                'out-errors'        : interface_counters['out_errors'        ],
+                'out-multicast-pkts': interface_counters['out_multicast_pkts'],
+                'out-octets'        : interface_counters['out_octets'        ],
+                'out-pkts'          : interface_counters['out_pkts'          ],
+                'out-unicast-pkts'  : interface_counters['out_unicast_pkts'  ],
+            }
+            LOGGER.debug('interface = {:s}'.format(str(interface)))
+
+            entry_interface_key = '/interface[{:s}]'.format(interface_name)
+            entries.append((entry_interface_key, _interface))
+
+        return entries
diff --git a/src/telemetry/backend/collectors/gnmi_openconfig/handlers/NetworkInstance.py b/src/telemetry/backend/collectors/gnmi_openconfig/handlers/NetworkInstance.py
new file mode 100644
index 0000000000000000000000000000000000000000..5d56dde8c0a4b37a3179970303469d6a80d61ad1
--- /dev/null
+++ b/src/telemetry/backend/collectors/gnmi_openconfig/handlers/NetworkInstance.py
@@ -0,0 +1,175 @@
+# Copyright 2022-2024 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/)
+#
+# 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.
+
+import json, libyang, logging
+from typing import Any, Dict, List, Tuple
+from ._Handler import _Handler
+from .Tools import get_str
+from .YangHandler import YangHandler
+
+LOGGER = logging.getLogger(__name__)
+
+MAP_NETWORK_INSTANCE_TYPE = {
+    # special routing instance; acts as default/global routing instance for a network device
+    'DEFAULT': 'openconfig-network-instance-types:DEFAULT_INSTANCE',
+
+    # private L3-only routing instance; formed of one or more RIBs
+    'L3VRF': 'openconfig-network-instance-types:L3VRF',
+
+    # private L2-only switch instance; formed of one or more L2 forwarding tables
+    'L2VSI': 'openconfig-network-instance-types:L2VSI',
+
+    # private L2-only forwarding instance; point to point connection between two endpoints
+    'L2P2P': 'openconfig-network-instance-types:L2P2P',
+
+    # private Layer 2 and Layer 3 forwarding instance
+    'L2L3': 'openconfig-network-instance-types:L2L3',
+}
+
+class NetworkInstanceHandler(_Handler):
+    def get_resource_key(self) -> str: return '/network_instance'
+    def get_path(self) -> str: return '/openconfig-network-instance:network-instances'
+
+    def compose(
+        self, resource_key : str, resource_value : Dict, yang_handler : YangHandler, delete : bool = False
+    ) -> Tuple[str, str]:
+        ni_name = get_str(resource_value, 'name') # test-svc
+
+        if delete:
+            PATH_TMPL = '/network-instances/network-instance[name={:s}]'
+            str_path = PATH_TMPL.format(ni_name)
+            str_data = json.dumps({})
+            return str_path, str_data
+
+        ni_type = get_str(resource_value, 'type') # L3VRF / L2VSI / ...
+        ni_type = MAP_NETWORK_INSTANCE_TYPE.get(ni_type, ni_type)
+
+        str_path = '/network-instances/network-instance[name={:s}]'.format(ni_name)
+        #str_data = json.dumps({
+        #    'name': ni_name,
+        #    'config': {'name': ni_name, 'type': ni_type},
+        #})
+
+        yang_nis : libyang.DContainer = yang_handler.get_data_path('/openconfig-network-instance:network-instances')
+        yang_ni_path = 'network-instance[name="{:s}"]'.format(ni_name)
+        yang_ni : libyang.DContainer = yang_nis.create_path(yang_ni_path)
+        yang_ni.create_path('config/name', ni_name)
+        yang_ni.create_path('config/type', ni_type)
+
+        # 'DIRECTLY_CONNECTED' is implicitly added
+        #'protocols': {'protocol': protocols},
+
+        str_data = yang_ni.print_mem('json')
+        json_data = json.loads(str_data)
+        json_data = json_data['openconfig-network-instance:network-instance'][0]
+        str_data = json.dumps(json_data)
+        return str_path, str_data
+
+    def parse(
+        self, json_data : Dict, yang_handler : YangHandler
+    ) -> List[Tuple[str, Dict[str, Any]]]:
+        LOGGER.debug('json_data = {:s}'.format(json.dumps(json_data)))
+
+        # Arista Parsing Fixes:
+        # - Default instance comes with mpls/signaling-protocols/rsvp-te/global/hellos/state/hello-interval set to 0
+        #   overwrite with .../hellos/config/hello-interval
+        network_instances = json_data.get('openconfig-network-instance:network-instance', [])
+        for network_instance in network_instances:
+            if network_instance['name'] != 'default': continue
+            mpls_rsvp_te = network_instance.get('mpls', {}).get('signaling-protocols', {}).get('rsvp-te', {})
+            mpls_rsvp_te_hellos = mpls_rsvp_te.get('global', {}).get('hellos', {})
+            hello_interval = mpls_rsvp_te_hellos.get('config', {}).get('hello-interval', 9000)
+            mpls_rsvp_te_hellos.get('state', {})['hello-interval'] = hello_interval
+
+        yang_network_instances_path = self.get_path()
+        json_data_valid = yang_handler.parse_to_dict(yang_network_instances_path, json_data, fmt='json', strict=False)
+
+        entries = []
+        for network_instance in json_data_valid['network-instances']['network-instance']:
+            LOGGER.debug('network_instance={:s}'.format(str(network_instance)))
+            ni_name = network_instance['name']
+
+            ni_config = network_instance['config']
+            ni_type = ni_config['type'].split(':')[-1]
+
+            _net_inst = {'name': ni_name, 'type': ni_type}
+            entry_net_inst_key = '/network_instance[{:s}]'.format(ni_name)
+            entries.append((entry_net_inst_key, _net_inst))
+
+            ni_interfaces = network_instance.get('interfaces', {}).get('interface', [])
+            for ni_interface in ni_interfaces:
+                #ni_if_id     = ni_interface['id']
+                ni_if_config = ni_interface['config']
+                ni_if_name   = ni_if_config['interface']
+                ni_sif_index = ni_if_config['subinterface']
+                ni_if_id     = '{:s}.{:d}'.format(ni_if_name, ni_sif_index)
+
+                _interface = {'name': ni_name, 'id': ni_if_id, 'if_name': ni_if_name, 'sif_index': ni_sif_index}
+                entry_interface_key = '{:s}/interface[{:s}]'.format(entry_net_inst_key, ni_if_id)
+                entries.append((entry_interface_key, _interface))
+
+            ni_protocols = network_instance.get('protocols', {}).get('protocol', [])
+            for ni_protocol in ni_protocols:
+                ni_protocol_id = ni_protocol['identifier'].split(':')[-1]
+                ni_protocol_name = ni_protocol['name']
+
+                _protocol = {'name': ni_name, 'identifier': ni_protocol_id, 'protocol_name': ni_protocol_name}
+                entry_protocol_key = '{:s}/protocols[{:s}]'.format(entry_net_inst_key, ni_protocol_id)
+                entries.append((entry_protocol_key, _protocol))
+
+                if ni_protocol_id == 'STATIC':
+                    static_routes = ni_protocol.get('static-routes', {}).get('static', [])
+                    for static_route in static_routes:
+                        static_route_prefix = static_route['prefix']
+                        for next_hop in static_route.get('next-hops', {}).get('next-hop', []):
+                            static_route_metric = next_hop['config']['metric']
+                            _static_route = {
+                                'prefix'  : static_route_prefix,
+                                'index'   : next_hop['index'],
+                                'next_hop': next_hop['config']['next-hop'],
+                                'metric'  : static_route_metric,
+                            }
+                            _static_route.update(_protocol)
+                            entry_static_route_key = '{:s}/static_route[{:s}:{:d}]'.format(
+                                entry_protocol_key, static_route_prefix, static_route_metric
+                            )
+                            entries.append((entry_static_route_key, _static_route))
+
+            ni_tables = network_instance.get('tables', {}).get('table', [])
+            for ni_table in ni_tables:
+                ni_table_protocol = ni_table['protocol'].split(':')[-1]
+                ni_table_address_family = ni_table['address-family'].split(':')[-1]
+                _table = {'protocol': ni_table_protocol, 'address_family': ni_table_address_family}
+                entry_table_key = '{:s}/table[{:s},{:s}]'.format(
+                    entry_net_inst_key, ni_table_protocol, ni_table_address_family
+                )
+                entries.append((entry_table_key, _table))
+
+            ni_vlans = network_instance.get('vlans', {}).get('vlan', [])
+            for ni_vlan in ni_vlans:
+                ni_vlan_id = ni_vlan['vlan-id']
+
+                #ni_vlan_config = ni_vlan['config']
+                ni_vlan_state = ni_vlan['state']
+                ni_vlan_name = ni_vlan_state['name']
+
+                _members = [
+                    member['state']['interface']
+                    for member in ni_vlan.get('members', {}).get('member', [])
+                ]
+                _vlan = {'vlan_id': ni_vlan_id, 'name': ni_vlan_name, 'members': _members}
+                entry_vlan_key = '{:s}/vlan[{:d}]'.format(entry_net_inst_key, ni_vlan_id)
+                entries.append((entry_vlan_key, _vlan))
+
+        return entries
diff --git a/src/telemetry/backend/collectors/gnmi_openconfig/handlers/NetworkInstanceInterface.py b/src/telemetry/backend/collectors/gnmi_openconfig/handlers/NetworkInstanceInterface.py
new file mode 100644
index 0000000000000000000000000000000000000000..f6f61a32403f154578da0247d0e1db24a727b017
--- /dev/null
+++ b/src/telemetry/backend/collectors/gnmi_openconfig/handlers/NetworkInstanceInterface.py
@@ -0,0 +1,71 @@
+# Copyright 2022-2024 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/)
+#
+# 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.
+
+import json, libyang, logging
+from typing import Any, Dict, List, Tuple
+from ._Handler import _Handler
+from .Tools import get_int, get_str
+from .YangHandler import YangHandler
+
+LOGGER = logging.getLogger(__name__)
+
+IS_CEOS = True
+
+class NetworkInstanceInterfaceHandler(_Handler):
+    def get_resource_key(self) -> str: return '/network_instance/interface'
+    def get_path(self) -> str: return '/openconfig-network-instance:network-instances/network-instance/interfaces'
+
+    def compose(
+        self, resource_key : str, resource_value : Dict, yang_handler : YangHandler, delete : bool = False
+    ) -> Tuple[str, str]:
+        ni_name   = get_str(resource_value, 'name'           ) # test-svc
+        ni_if_id  = get_str(resource_value, 'id'             ) # ethernet-1/1.0
+        if_name   = get_str(resource_value, 'interface'      ) # ethernet-1/1
+        sif_index = get_int(resource_value, 'subinterface', 0) # 0
+
+        if IS_CEOS: ni_if_id = if_name
+
+        PATH_TMPL = '/network-instances/network-instance[name={:s}]/interfaces/interface[id={:s}]'
+        str_path = PATH_TMPL.format(ni_name, ni_if_id)
+
+        if delete:
+            str_data = json.dumps({})
+            return str_path, str_data
+
+        #str_data = json.dumps({
+        #    'id': if_id,
+        #    'config': {'id': if_id, 'interface': if_name, 'subinterface': sif_index},
+        #})
+
+        yang_nis : libyang.DContainer = yang_handler.get_data_path('/openconfig-network-instance:network-instances')
+        yang_ni : libyang.DContainer = yang_nis.create_path('network-instance[name="{:s}"]'.format(ni_name))
+        yang_ni_ifs : libyang.DContainer = yang_ni.create_path('interfaces')
+        yang_ni_if_path = 'interface[id="{:s}"]'.format(ni_if_id)
+        yang_ni_if : libyang.DContainer = yang_ni_ifs.create_path(yang_ni_if_path)
+        yang_ni_if.create_path('config/id',           ni_if_id)
+        yang_ni_if.create_path('config/interface',    if_name)
+        yang_ni_if.create_path('config/subinterface', sif_index)
+
+        str_data = yang_ni_if.print_mem('json')
+        json_data = json.loads(str_data)
+        json_data = json_data['openconfig-network-instance:interface'][0]
+        str_data = json.dumps(json_data)
+        return str_path, str_data
+
+    def parse(
+        self, json_data : Dict, yang_handler : YangHandler
+    ) -> List[Tuple[str, Dict[str, Any]]]:
+        LOGGER.debug('[parse] json_data = {:s}'.format(str(json_data)))
+        response = []
+        return response
diff --git a/src/telemetry/backend/collectors/gnmi_openconfig/handlers/NetworkInstanceProtocol.py b/src/telemetry/backend/collectors/gnmi_openconfig/handlers/NetworkInstanceProtocol.py
new file mode 100644
index 0000000000000000000000000000000000000000..854bb4fd2df68c47c4291ed51ed012522c1a3a2d
--- /dev/null
+++ b/src/telemetry/backend/collectors/gnmi_openconfig/handlers/NetworkInstanceProtocol.py
@@ -0,0 +1,79 @@
+# Copyright 2022-2024 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/)
+#
+# 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.
+
+import json, libyang, logging
+from typing import Any, Dict, List, Tuple
+from ._Handler import _Handler
+from .Tools import get_str
+from .YangHandler import YangHandler
+
+LOGGER = logging.getLogger(__name__)
+
+class NetworkInstanceProtocolHandler(_Handler):
+    def get_resource_key(self) -> str: return '/network_instance/protocols'
+    def get_path(self) -> str:
+        return '/openconfig-network-instance:network-instances/network-instance/protocols/protocol'
+
+    def compose(
+        self, resource_key : str, resource_value : Dict, yang_handler : YangHandler, delete : bool = False
+    ) -> Tuple[str, str]:
+        ni_name    = get_str(resource_value, 'name'  )          # test-svc
+        identifier = get_str(resource_value, 'identifier')      # 'STATIC'
+        proto_name = get_str(resource_value, 'protocol_name')   # 'STATIC'
+
+        if ':' not in identifier:
+            identifier = 'openconfig-policy-types:{:s}'.format(identifier)
+        PATH_TMPL = '/network-instances/network-instance[name={:s}]/protocols/protocol[identifier={:s}][name={:s}]'
+        str_path = PATH_TMPL.format(ni_name, identifier, proto_name)
+
+        if delete:
+            str_data = json.dumps({})
+            return str_path, str_data
+
+        #str_data = json.dumps({
+        #    'identifier': identifier, 'name': name,
+        #    'config': {'identifier': identifier, 'name': name, 'enabled': True},
+        #    'static_routes': {'static': [{
+        #        'prefix': prefix,
+        #        'config': {'prefix': prefix},
+        #        'next_hops': {
+        #            'next-hop': [{
+        #                'index': next_hop_index,
+        #                'config': {'index': next_hop_index, 'next_hop': next_hop}
+        #            }]
+        #        }
+        #    }]}
+        #})
+
+        yang_nis : libyang.DContainer = yang_handler.get_data_path('/openconfig-network-instance:network-instances')
+        yang_ni : libyang.DContainer = yang_nis.create_path('network-instance[name="{:s}"]'.format(ni_name))
+        yang_ni_prs : libyang.DContainer = yang_ni.create_path('protocols')
+        yang_ni_pr_path = 'protocol[identifier="{:s}"][name="{:s}"]'.format(identifier, proto_name)
+        yang_ni_pr : libyang.DContainer = yang_ni_prs.create_path(yang_ni_pr_path)
+        yang_ni_pr.create_path('config/identifier', identifier)
+        yang_ni_pr.create_path('config/name',       proto_name)
+        yang_ni_pr.create_path('config/enabled',    True      )
+
+        str_data = yang_ni_pr.print_mem('json')
+        json_data = json.loads(str_data)
+        json_data = json_data['openconfig-network-instance:protocol'][0]
+        str_data = json.dumps(json_data)
+        return str_path, str_data
+
+    def parse(
+        self, json_data : Dict, yang_handler : YangHandler
+    ) -> List[Tuple[str, Dict[str, Any]]]:
+        LOGGER.debug('[parse] json_data = {:s}'.format(str(json_data)))
+        response = []
+        return response
diff --git a/src/telemetry/backend/collectors/gnmi_openconfig/handlers/NetworkInstanceStaticRoute.py b/src/telemetry/backend/collectors/gnmi_openconfig/handlers/NetworkInstanceStaticRoute.py
new file mode 100644
index 0000000000000000000000000000000000000000..cb4b68a1e82774350d7a16accf9ad7ef1ad2ac1a
--- /dev/null
+++ b/src/telemetry/backend/collectors/gnmi_openconfig/handlers/NetworkInstanceStaticRoute.py
@@ -0,0 +1,101 @@
+# Copyright 2022-2024 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/)
+#
+# 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.
+
+import json, libyang, logging
+from typing import Any, Dict, List, Tuple
+from ._Handler import _Handler
+from .Tools import get_int, get_str
+from .YangHandler import YangHandler
+
+LOGGER = logging.getLogger(__name__)
+
+class NetworkInstanceStaticRouteHandler(_Handler):
+    def get_resource_key(self) -> str: return '/network_instance/protocols/static_route'
+    def get_path(self) -> str:
+        return '/openconfig-network-instance:network-instances/network-instance/protocols/protocol/static-routes'
+
+    def compose(
+        self, resource_key : str, resource_value : Dict, yang_handler : YangHandler, delete : bool = False
+    ) -> Tuple[str, str]:
+        ni_name    = get_str(resource_value, 'name'  )          # test-svc
+        identifier = get_str(resource_value, 'identifier')      # 'STATIC'
+        proto_name = get_str(resource_value, 'protocol_name')   # 'STATIC'
+        prefix     = get_str(resource_value, 'prefix')          # '172.0.1.0/24'
+
+        if ':' not in identifier:
+            identifier = 'openconfig-policy-types:{:s}'.format(identifier)
+
+        if delete:
+            PATH_TMPL  = '/network-instances/network-instance[name={:s}]/protocols'
+            PATH_TMPL += '/protocol[identifier={:s}][name={:s}]/static-routes/static[prefix={:s}]'
+            str_path = PATH_TMPL.format(ni_name, identifier, proto_name, prefix)
+            str_data = json.dumps({})
+            return str_path, str_data
+
+        next_hop = get_str(resource_value, 'next_hop')  # '172.0.0.1'
+        metric   = get_int(resource_value, 'metric'  )  # 20
+        index    = get_str(resource_value, 'index'   )  # AUTO_1_172-0-0-1
+        if index is None:
+            index = 'AUTO_{:d}_{:s}'.format(metric, next_hop)
+
+        PATH_TMPL = '/network-instances/network-instance[name={:s}]/protocols/protocol[identifier={:s}][name={:s}]'
+        str_path = PATH_TMPL.format(ni_name, identifier, proto_name)
+        #str_data = json.dumps({
+        #    'identifier': identifier, 'name': name,
+        #    'config': {'identifier': identifier, 'name': name, 'enabled': True},
+        #    'static_routes': {'static': [{
+        #        'prefix': prefix,
+        #        'config': {'prefix': prefix},
+        #        'next_hops': {
+        #            'next-hop': [{
+        #                'index': next_hop_index,
+        #                'config': {'index': next_hop_index, 'next_hop': next_hop}
+        #            }]
+        #        }
+        #    }]}
+        #})
+
+        yang_nis : libyang.DContainer = yang_handler.get_data_path('/openconfig-network-instance:network-instances')
+        yang_ni : libyang.DContainer = yang_nis.create_path('network-instance[name="{:s}"]'.format(ni_name))
+        yang_ni_prs : libyang.DContainer = yang_ni.create_path('protocols')
+        yang_ni_pr_path = 'protocol[identifier="{:s}"][name="{:s}"]'.format(identifier, proto_name)
+        yang_ni_pr : libyang.DContainer = yang_ni_prs.create_path(yang_ni_pr_path)
+        yang_ni_pr.create_path('config/identifier', identifier)
+        yang_ni_pr.create_path('config/name',       proto_name)
+        yang_ni_pr.create_path('config/enabled',    True      )
+
+        yang_ni_pr_srs : libyang.DContainer = yang_ni_pr.create_path('static-routes')
+        yang_ni_pr_sr_path = 'static[prefix="{:s}"]'.format(prefix)
+        yang_ni_pr_sr : libyang.DContainer = yang_ni_pr_srs.create_path(yang_ni_pr_sr_path)
+        yang_ni_pr_sr.create_path('config/prefix', prefix)
+
+        yang_ni_pr_sr_nhs : libyang.DContainer = yang_ni_pr_sr.create_path('next-hops')
+        yang_ni_pr_sr_nh_path = 'next-hop[index="{:s}"]'.format(index)
+        yang_ni_pr_sr_nh : libyang.DContainer = yang_ni_pr_sr_nhs.create_path(yang_ni_pr_sr_nh_path)
+        yang_ni_pr_sr_nh.create_path('config/index',    index)
+        yang_ni_pr_sr_nh.create_path('config/next-hop', next_hop)
+        yang_ni_pr_sr_nh.create_path('config/metric',   metric)
+
+        str_data = yang_ni_pr.print_mem('json')
+        json_data = json.loads(str_data)
+        json_data = json_data['openconfig-network-instance:protocol'][0]
+        str_data = json.dumps(json_data)
+        return str_path, str_data
+
+    def parse(
+        self, json_data : Dict, yang_handler : YangHandler
+    ) -> List[Tuple[str, Dict[str, Any]]]:
+        LOGGER.debug('[parse] json_data = {:s}'.format(str(json_data)))
+        response = []
+        return response
diff --git a/src/telemetry/backend/collectors/gnmi_openconfig/handlers/Tools.py b/src/telemetry/backend/collectors/gnmi_openconfig/handlers/Tools.py
new file mode 100644
index 0000000000000000000000000000000000000000..d07a097f6f1ebc008c370a524df4e7511cbe2b46
--- /dev/null
+++ b/src/telemetry/backend/collectors/gnmi_openconfig/handlers/Tools.py
@@ -0,0 +1,61 @@
+# Copyright 2022-2024 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/)
+#
+# 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.
+
+import re
+from typing import Any, Callable, Dict, Iterable, Optional
+
+RE_REMOVE_FILTERS = re.compile(r'\[[^\]]+\]')
+RE_REMOVE_NAMESPACES = re.compile(r'\/[a-zA-Z0-9\_\-]+:')
+
+def get_schema(resource_key : str):
+    resource_key = RE_REMOVE_FILTERS.sub('', resource_key)
+    resource_key = RE_REMOVE_NAMESPACES.sub('/', resource_key)
+    return resource_key
+
+def container_get_first(
+    container : Dict[str, Any], key_name : str, namespace : Optional[str]=None, namespaces : Iterable[str]=tuple(),
+    default : Optional[Any] = None
+) -> Any:
+    value = container.get(key_name)
+    if value is not None: return value
+
+    if namespace is not None:
+        if len(namespaces) > 0:
+            raise Exception('At maximum, one of namespace or namespaces can be specified')
+        namespaces = (namespace,)
+
+    for namespace in namespaces:
+        namespace_key_name = '{:s}:{:s}'.format(namespace, key_name)
+        if namespace_key_name in container: return container[namespace_key_name]
+
+    return default
+
+def get_value(
+    resource_value : Dict, field_name : str, cast_func : Callable = lambda x:x, default : Optional[Any] = None
+) -> Optional[Any]:
+    field_value = resource_value.get(field_name, default)
+    if field_value is not None: field_value = cast_func(field_value)
+    return field_value
+
+def get_bool(resource_value : Dict, field_name : bool, default : Optional[Any] = None) -> bool:
+    return get_value(resource_value, field_name, cast_func=bool, default=default)
+
+def get_float(resource_value : Dict, field_name : float, default : Optional[Any] = None) -> float:
+    return get_value(resource_value, field_name, cast_func=float, default=default)
+
+def get_int(resource_value : Dict, field_name : int, default : Optional[Any] = None) -> int:
+    return get_value(resource_value, field_name, cast_func=int, default=default)
+
+def get_str(resource_value : Dict, field_name : str, default : Optional[Any] = None) -> str:
+    return get_value(resource_value, field_name, cast_func=str, default=default)
diff --git a/src/telemetry/backend/collectors/gnmi_openconfig/handlers/YangHandler.py b/src/telemetry/backend/collectors/gnmi_openconfig/handlers/YangHandler.py
new file mode 100644
index 0000000000000000000000000000000000000000..e7cff19eb901be4a85d4e31f8de9070fe5a7c277
--- /dev/null
+++ b/src/telemetry/backend/collectors/gnmi_openconfig/handlers/YangHandler.py
@@ -0,0 +1,110 @@
+# Copyright 2022-2024 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/)
+#
+# 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.
+
+import json, libyang, logging, os
+from typing import Dict, Optional
+
+YANG_BASE_PATH = os.path.join(os.path.dirname(__file__), '..', 'git', 'openconfig', 'public')
+YANG_SEARCH_PATHS = ':'.join([
+    os.path.join(YANG_BASE_PATH, 'release'),
+    os.path.join(YANG_BASE_PATH, 'third_party'),
+])
+
+YANG_MODULES = [
+    'iana-if-type',
+    'openconfig-bgp-types',
+    'openconfig-vlan-types',
+
+    'openconfig-interfaces',
+    'openconfig-if-8021x',
+    'openconfig-if-aggregate',
+    'openconfig-if-ethernet-ext',
+    'openconfig-if-ethernet',
+    'openconfig-if-ip-ext',
+    'openconfig-if-ip',
+    'openconfig-if-poe',
+    'openconfig-if-sdn-ext',
+    'openconfig-if-tunnel',
+
+    'openconfig-vlan',
+
+    'openconfig-types',
+    'openconfig-policy-types',
+    'openconfig-mpls-types',
+    'openconfig-network-instance-types',
+    'openconfig-network-instance',
+
+    'openconfig-platform',
+    'openconfig-platform-controller-card',
+    'openconfig-platform-cpu',
+    'openconfig-platform-ext',
+    'openconfig-platform-fabric',
+    'openconfig-platform-fan',
+    'openconfig-platform-integrated-circuit',
+    'openconfig-platform-linecard',
+    'openconfig-platform-pipeline-counters',
+    'openconfig-platform-port',
+    'openconfig-platform-psu',
+    'openconfig-platform-software',
+    'openconfig-platform-transceiver',
+    'openconfig-platform-types',
+]
+
+LOGGER = logging.getLogger(__name__)
+
+class YangHandler:
+    def __init__(self) -> None:
+        self._yang_context = libyang.Context(YANG_SEARCH_PATHS)
+        self._loaded_modules = set()
+        for yang_module_name in YANG_MODULES:
+            LOGGER.info('Loading module: {:s}'.format(str(yang_module_name)))
+            self._yang_context.load_module(yang_module_name).feature_enable_all()
+            self._loaded_modules.add(yang_module_name)
+        self._data_path_instances = dict()
+
+    def get_data_paths(self) -> Dict[str, libyang.DNode]:
+        return self._data_path_instances
+
+    def get_data_path(self, path : str) -> libyang.DNode:
+        data_path_instance = self._data_path_instances.get(path)
+        if data_path_instance is None:
+            data_path_instance = self._yang_context.create_data_path(path)
+            self._data_path_instances[path] = data_path_instance
+        return data_path_instance
+
+    def parse_to_dict(
+        self, request_path : str, json_data : Dict, fmt : str = 'json', strict : bool = True
+    ) -> Dict:
+        if fmt != 'json': raise Exception('Unsupported format: {:s}'.format(str(fmt)))
+        LOGGER.debug('request_path = {:s}'.format(str(request_path)))
+        LOGGER.debug('json_data = {:s}'.format(str(json_data)))
+        LOGGER.debug('format = {:s}'.format(str(fmt)))
+
+        parent_path_parts = list(filter(lambda s: len(s) > 0, request_path.split('/')))
+        for parent_path_part in reversed(parent_path_parts):
+            json_data = {parent_path_part: json_data}
+        str_data = json.dumps(json_data)
+
+        dnode : Optional[libyang.DNode] = self._yang_context.parse_data_mem(
+            str_data, fmt, strict=strict, parse_only=True, #validate_present=True, #validate=True,
+        )
+        if dnode is None: raise Exception('Unable to parse Data({:s})'.format(str(json_data)))
+
+        parsed = dnode.print_dict()
+        LOGGER.debug('parsed = {:s}'.format(json.dumps(parsed)))
+        dnode.free()
+        return parsed
+
+    def destroy(self) -> None:
+        self._yang_context.destroy()
diff --git a/src/telemetry/backend/collectors/gnmi_openconfig/handlers/_Handler.py b/src/telemetry/backend/collectors/gnmi_openconfig/handlers/_Handler.py
new file mode 100644
index 0000000000000000000000000000000000000000..3d9d0ade1f70d6b359c53838567b5d0a6ed7e038
--- /dev/null
+++ b/src/telemetry/backend/collectors/gnmi_openconfig/handlers/_Handler.py
@@ -0,0 +1,37 @@
+# Copyright 2022-2024 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/)
+#
+# 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.
+
+from typing import Any, Dict, List, Tuple
+from .YangHandler import YangHandler
+
+class _Handler:
+    def get_resource_key(self) -> str:
+        # Retrieve the TeraFlowSDN resource_key path schema used to point this handler
+        raise NotImplementedError()
+
+    def get_path(self) -> str:
+        # Retrieve the OpenConfig path schema used to interrogate the device
+        raise NotImplementedError()
+
+    def compose(
+        self, resource_key : str, resource_value : Dict, yang_handler : YangHandler, delete : bool = False
+    ) -> Tuple[str, str]:
+        # Compose a Set/Delete message based on the resource_key/resource_value fields, and the delete flag
+        raise NotImplementedError()
+
+    def parse(
+        self, json_data : Dict, yang_handler : YangHandler
+    ) -> List[Tuple[str, Dict[str, Any]]]:
+        # Parse a Reply from the device and return a list of resource_key/resource_value pairs
+        raise NotImplementedError()
diff --git a/src/telemetry/backend/collectors/gnmi_openconfig/handlers/__init__.py b/src/telemetry/backend/collectors/gnmi_openconfig/handlers/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..6af371cebffb4870004cb5d9e249f0bca3aaf035
--- /dev/null
+++ b/src/telemetry/backend/collectors/gnmi_openconfig/handlers/__init__.py
@@ -0,0 +1,118 @@
+# Copyright 2022-2024 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/)
+#
+# 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.
+
+import logging
+from typing import Any, Dict, List, Optional, Tuple, Union
+from device.service.driver_api._Driver import RESOURCE_ENDPOINTS, RESOURCE_INTERFACES, RESOURCE_NETWORK_INSTANCES
+from ._Handler import _Handler
+from .Component import ComponentHandler
+from .Interface import InterfaceHandler
+from .InterfaceCounter import InterfaceCounterHandler
+from .NetworkInstance import NetworkInstanceHandler
+from .NetworkInstanceInterface import NetworkInstanceInterfaceHandler
+from .NetworkInstanceProtocol import NetworkInstanceProtocolHandler
+from .NetworkInstanceStaticRoute import NetworkInstanceStaticRouteHandler
+from .Tools import get_schema
+from .YangHandler import YangHandler
+
+LOGGER = logging.getLogger(__name__)
+
+comph  = ComponentHandler()
+ifaceh = InterfaceHandler()
+ifctrh = InterfaceCounterHandler()
+nih    = NetworkInstanceHandler()
+niifh  = NetworkInstanceInterfaceHandler()
+niph   = NetworkInstanceProtocolHandler()
+nisrh  = NetworkInstanceStaticRouteHandler()
+
+ALL_RESOURCE_KEYS = [
+    RESOURCE_ENDPOINTS,
+    RESOURCE_INTERFACES,
+    RESOURCE_NETWORK_INSTANCES,
+]
+
+RESOURCE_KEY_MAPPER = {
+    RESOURCE_ENDPOINTS         : comph.get_resource_key(),
+    RESOURCE_INTERFACES        : ifaceh.get_resource_key(),
+    RESOURCE_NETWORK_INSTANCES : nih.get_resource_key(),
+}
+
+PATH_MAPPER = {
+    '/components'           : comph.get_path(),
+    '/components/component' : comph.get_path(),
+    '/interfaces'           : ifaceh.get_path(),
+    '/network-instances'    : nih.get_path(),
+}
+
+RESOURCE_KEY_TO_HANDLER = {
+    comph.get_resource_key()  : comph,
+    ifaceh.get_resource_key() : ifaceh,
+    ifctrh.get_resource_key() : ifctrh,
+    nih.get_resource_key()    : nih,
+    niifh.get_resource_key()  : niifh,
+    niph.get_resource_key()   : niph,
+    nisrh.get_resource_key()  : nisrh,
+}
+
+PATH_TO_HANDLER = {
+    comph.get_path()  : comph,
+    ifaceh.get_path() : ifaceh,
+    ifctrh.get_path() : ifctrh,
+    nih.get_path()    : nih,
+    niifh.get_path()  : niifh,
+    niph.get_path()   : niph,
+    nisrh.get_path()  : nisrh,
+}
+
+def get_handler(
+    resource_key : Optional[str] = None, path : Optional[str] = None,
+    raise_if_not_found=True
+) -> Optional[_Handler]:
+    if (resource_key is None) == (path is None):
+        MSG = 'Exactly one of resource_key({:s}) or path({:s}) must be specified'
+        raise Exception(MSG.format(str(resource_key), str(path))) # pylint: disable=broad-exception-raised
+    if resource_key is not None:
+        resource_key_schema = get_schema(resource_key)
+        resource_key_schema = RESOURCE_KEY_MAPPER.get(resource_key_schema, resource_key_schema)
+        handler = RESOURCE_KEY_TO_HANDLER.get(resource_key_schema)
+        if handler is None and raise_if_not_found:
+            MSG = 'Handler not found: resource_key={:s} resource_key_schema={:s}'
+            # pylint: disable=broad-exception-raised
+            raise Exception(MSG.format(str(resource_key), str(resource_key_schema)))
+    elif path is not None:
+        path_schema = get_schema(path)
+        path_schema = PATH_MAPPER.get(path_schema, path_schema)
+        handler = PATH_TO_HANDLER.get(path_schema)
+        if handler is None and raise_if_not_found:
+            MSG = 'Handler not found: path={:s} path_schema={:s}'
+            # pylint: disable=broad-exception-raised
+            raise Exception(MSG.format(str(path), str(path_schema)))
+    return handler
+
+def get_path(resource_key : str) -> str:
+    handler = get_handler(resource_key=resource_key)
+    return handler.get_path()
+
+def parse(
+    str_path : str, value : Union[Dict, List], yang_handler : YangHandler
+) -> List[Tuple[str, Dict[str, Any]]]:
+    handler = get_handler(path=str_path)
+    return handler.parse(value, yang_handler)
+
+def compose(
+    resource_key : str, resource_value : Union[Dict, List],
+    yang_handler : YangHandler, delete : bool = False
+) -> Tuple[str, str]:
+    handler = get_handler(resource_key=resource_key)
+    return handler.compose(resource_key, resource_value, yang_handler, delete=delete)
diff --git a/src/telemetry/backend/collectors/gnmi_openconfig/tools/Capabilities.py b/src/telemetry/backend/collectors/gnmi_openconfig/tools/Capabilities.py
new file mode 100644
index 0000000000000000000000000000000000000000..a57f0d731667364693c0e337ca2bda92e68068a8
--- /dev/null
+++ b/src/telemetry/backend/collectors/gnmi_openconfig/tools/Capabilities.py
@@ -0,0 +1,49 @@
+# Copyright 2022-2024 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/)
+#
+# 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.
+
+from typing import Optional, Set, Union
+from common.tools.grpc.Tools import grpc_message_to_json
+from ..gnmi.gnmi_pb2 import CapabilityRequest   # pylint: disable=no-name-in-module
+from ..gnmi.gnmi_pb2_grpc import gNMIStub
+
+def check_capabilities(
+    stub : gNMIStub, username : str, password : str, timeout : Optional[int] = None
+) -> Set[Union[str, int]]:
+    metadata = [('username', username), ('password', password)]
+    req = CapabilityRequest()
+    reply = stub.Capabilities(req, metadata=metadata, timeout=timeout)
+
+    data = grpc_message_to_json(reply)
+
+    gnmi_version = data.get('gNMI_version')
+    if gnmi_version is None or gnmi_version != '0.7.0':
+        raise Exception('Unsupported gNMI version: {:s}'.format(str(gnmi_version)))
+
+    #supported_models = {
+    #    supported_model['name']: supported_model['version']
+    #    for supported_model in data.get('supported_models', [])
+    #}
+    # TODO: check supported models and versions
+
+    supported_encodings = {
+        supported_encoding
+        for supported_encoding in data.get('supported_encodings', [])
+        if isinstance(supported_encoding, str)
+    }
+    if len(supported_encodings) == 0:
+        # pylint: disable=broad-exception-raised
+        raise Exception('No supported encodings found')
+    if 'JSON_IETF' not in supported_encodings:
+        # pylint: disable=broad-exception-raised
+        raise Exception('JSON_IETF encoding not supported')
diff --git a/src/telemetry/backend/collectors/gnmi_openconfig/tools/Channel.py b/src/telemetry/backend/collectors/gnmi_openconfig/tools/Channel.py
new file mode 100644
index 0000000000000000000000000000000000000000..93893f6405a63c4730e23f8dd009645abcc2b5eb
--- /dev/null
+++ b/src/telemetry/backend/collectors/gnmi_openconfig/tools/Channel.py
@@ -0,0 +1,34 @@
+# Copyright 2022-2024 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/)
+#
+# 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.
+
+import grpc, logging, ssl
+
+def get_grpc_channel(address : str, port : int, use_tls : bool, logger : logging.Logger) -> grpc.Channel:
+    endpoint = str(address) + ':' + str(port)
+    logger.info('Connecting gNMI {:s}...'.format(endpoint))
+    if use_tls:
+        logger.debug('Getting server certificate...')
+        str_server_certificate = ssl.get_server_certificate((str(address), int(port)))
+        bytes_server_certificate = str_server_certificate.encode('UTF-8')
+        logger.debug('Using secure SSL channel...')
+        credentials = grpc.ssl_channel_credentials(
+            root_certificates=bytes_server_certificate, private_key=None, certificate_chain=None)
+        options = [
+            #('grpc.ssl_target_name_override', options.altName,)
+        ]
+        channel = grpc.secure_channel(endpoint, credentials, options)
+    else:
+        logger.debug('Using insecure channel...')
+        channel = grpc.insecure_channel(endpoint)
+    return channel
diff --git a/src/telemetry/backend/collectors/gnmi_openconfig/tools/Path.py b/src/telemetry/backend/collectors/gnmi_openconfig/tools/Path.py
new file mode 100644
index 0000000000000000000000000000000000000000..a9d47a2aca492bbd6dbc18d26fba9a4788cbd16c
--- /dev/null
+++ b/src/telemetry/backend/collectors/gnmi_openconfig/tools/Path.py
@@ -0,0 +1,98 @@
+# Copyright 2022-2024 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/)
+#
+# 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.
+
+import re
+from typing import List
+from ..gnmi.gnmi_pb2 import Path, PathElem
+
+RE_PATH_SPLIT = re.compile(r'/(?=(?:[^\[\]]|\[[^\[\]]+\])*$)')
+RE_PATH_KEYS = re.compile(r'\[(.*?)\]')
+
+def path_from_string(path='/'): #, origin='openconfig'
+    if not path: return Path(elem=[]) #, origin=origin
+
+    if path[0] == '/':
+        if path[-1] == '/':
+            path_list = RE_PATH_SPLIT.split(path)[1:-1]
+        else:
+            path_list = RE_PATH_SPLIT.split(path)[1:]
+    else:
+        if path[-1] == '/':
+            path_list = RE_PATH_SPLIT.split(path)[:-1]
+        else:
+            path_list = RE_PATH_SPLIT.split(path)
+
+    path = []
+    for elem in path_list:
+        elem_name = elem.split('[', 1)[0]
+        elem_keys = RE_PATH_KEYS.findall(elem)
+        dict_keys = dict(x.split('=', 1) for x in elem_keys)
+        path.append(PathElem(name=elem_name, key=dict_keys))
+
+    return Path(elem=path) #, origin=origin
+
+def path_to_string(path : Path) -> str:
+    path_parts = list()
+    for elem in path.elem:
+        kv_list = list()
+        for key in elem.key:
+            value = elem.key[key]
+            kv = '{:s}={:s}'.format(key, value)
+            kv_list.append(kv)
+
+        path_part_name = elem.name
+        if len(kv_list) == 0:
+            path_parts.append(path_part_name)
+        else:
+            str_kv = ', '.join(kv_list)
+            path_part = '{:s}[{:s}]'.format(path_part_name, str_kv)
+            path_parts.append(path_part)
+
+    str_path = '/{:s}'.format('/'.join(path_parts))
+    return str_path
+
+def parse_xpath(xpath : str) -> str:
+    xpath = xpath.replace('//', '/')
+    xpath = xpath.replace('oci:interface[', 'interface[')
+    xpath = xpath.replace('/oci', '/openconfig-interfaces')
+    xpath = re.sub(r"\[oci:name='(.*?)'\]", r"[name=\1]", xpath)
+    # Eliminar el contador del final
+    xpath = '/'.join(xpath.split('/')[:-1]) + '/'
+    return xpath
+
+def split_resource_key(path):
+    pattern = r'/state/counters/(.*)'
+    match = re.search(pattern, path)
+    if match is None: return None
+    return match.group(1)
+
+def dict_to_xpath(d: dict) -> str:
+    xpath = '/'
+    for item in d['elem']:
+        name = item.get('name')
+        if name == 'interface':
+            key = item.get('key')
+            interface_name = key.get('name')
+            xpath += f"/oci:interface[oci:name='{interface_name}']"
+        else:
+            xpath += f"/{name}"
+    xpath = xpath.replace('openconfig-interfaces', 'oci')
+    return xpath
+
+def compose_path(base_path : str, path_filters : List[str] = []):
+    new_path = '' if base_path is None else str(base_path)
+    for path_filter in path_filters:
+        if path_filter == '': continue
+        new_path = '{:s}[{:s}]'.format(new_path, path_filter)
+    return new_path
diff --git a/src/telemetry/backend/collectors/gnmi_openconfig/tools/Subscriptions.py b/src/telemetry/backend/collectors/gnmi_openconfig/tools/Subscriptions.py
new file mode 100644
index 0000000000000000000000000000000000000000..21c8edd61af727eeedff7e8ef23411cf1a509706
--- /dev/null
+++ b/src/telemetry/backend/collectors/gnmi_openconfig/tools/Subscriptions.py
@@ -0,0 +1,47 @@
+# Copyright 2022-2024 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/)
+#
+# 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.
+
+# Collection of samples through NetConf is very slow and each request collects all the data.
+# Populate a cache periodically (when first interface is interrogated).
+# Evict data after some seconds, when data is considered as outdated
+
+import anytree
+from typing import Any, List
+from device.service.driver_api.AnyTreeTools import TreeNode, get_subnode, set_subnode_value
+
+class Subscriptions:
+    def __init__(self) -> None:
+        self.__resolver = anytree.Resolver(pathattr='name')
+        self.__subscriptions = TreeNode('.')
+    
+    def add(
+        self, resource_path : List[str], sampling_duration : float, sampling_interval : float, value : Any
+    ) -> None:
+        subscription_path = resource_path + ['{:.3f}:{:.3f}'.format(sampling_duration, sampling_interval)]
+        set_subnode_value(self.__resolver, self.__subscriptions, subscription_path, value)
+
+    def get(
+        self, resource_path : List[str], sampling_duration : float, sampling_interval : float
+    ) -> TreeNode:
+        subscription_path = resource_path + ['{:.3f}:{:.3f}'.format(sampling_duration, sampling_interval)]
+        value = get_subnode(self.__resolver, self.__subscriptions, subscription_path)
+        return value
+
+    def delete(
+        self, reference : TreeNode
+    ) -> None:
+        parent : TreeNode = reference.parent
+        children = list(parent.children)
+        children.remove(reference)
+        parent.children = tuple(children)
diff --git a/src/telemetry/backend/collectors/gnmi_openconfig/tools/Value.py b/src/telemetry/backend/collectors/gnmi_openconfig/tools/Value.py
new file mode 100644
index 0000000000000000000000000000000000000000..8337e6677a67d0c8d6eb2d2a684704d9d10c8854
--- /dev/null
+++ b/src/telemetry/backend/collectors/gnmi_openconfig/tools/Value.py
@@ -0,0 +1,83 @@
+# Copyright 2022-2024 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/)
+#
+# 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.
+
+import base64, json
+from typing import Any, Dict, List, Union
+from ..gnmi.gnmi_pb2 import TypedValue
+
+REMOVE_NAMESPACES = (
+    'arista-intf-augments',
+    'arista-netinst-augments',
+    'openconfig-hercules-platform',
+)
+
+def remove_fields(key : str) -> bool:
+    parts = key.split(':')
+    if len(parts) == 1: return False
+    namespace = parts[0].lower()
+    return namespace in REMOVE_NAMESPACES
+
+def recursive_remove_keys(container : Union[Dict, List, Any]) -> None:
+    if isinstance(container, dict):
+        remove_keys = [
+            key
+            for key in container.keys()
+            if remove_fields(key)
+        ]
+        for key in remove_keys:
+            container.pop(key, None)
+        for value in container.values():
+            recursive_remove_keys(value)
+    elif isinstance(container, list):
+        for value in container:
+            recursive_remove_keys(value)
+
+def decode_value(value : TypedValue) -> Any:
+    encoding = value.WhichOneof('value')
+    if encoding == 'json_val':
+        value = value.json_val
+        #mdl, cls = self._classes[className]
+        #obj = json.loads(strObj)
+        #if isinstance(obj, (list,)):
+        #    obj = map(lambda n: pybindJSON.loads(n, mdl, cls.__name__), obj)
+        #    data = map(lambda n: json.loads(pybindJSON.dumps(n, mode='default')), obj)
+        #else:
+        #    obj = pybindJSON.loads(obj, mdl, cls.__name__)
+        #    data = json.loads(pybindJSON.dumps(obj, mode='default'))
+        raise NotImplementedError()
+        #return value
+    elif encoding == 'json_ietf_val':
+        str_value : str = value.json_ietf_val.decode('UTF-8')
+        try:
+            # Cleanup and normalize the records according to OpenConfig
+            #str_value = str_value.replace('openconfig-platform-types:', 'oc-platform-types:')
+            json_value = json.loads(str_value)
+            recursive_remove_keys(json_value)
+            return json_value
+        except json.decoder.JSONDecodeError:
+            # Assume is Base64-encoded
+            b_b64_value = value.encode('UTF-8')
+            b_value = base64.b64decode(b_b64_value, validate=True)
+            value = b_value.decode('UTF-8')
+            return json.loads(value)
+    else:
+        MSG = 'Unsupported Encoding({:s}) in Value({:s})'
+        # pylint: disable=broad-exception-raised
+        raise Exception(MSG.format(str(encoding), str(value)))
+
+def value_exists(value) -> bool:
+    if value is None: return False
+    if isinstance(value, Exception): return False
+    if issubclass(type(value), Exception): return False
+    return True
diff --git a/src/telemetry/backend/collectors/gnmi_openconfig/tools/__init__.py b/src/telemetry/backend/collectors/gnmi_openconfig/tools/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..53d5157f750bfb085125cbd33faff1cec5924e14
--- /dev/null
+++ b/src/telemetry/backend/collectors/gnmi_openconfig/tools/__init__.py
@@ -0,0 +1,14 @@
+# Copyright 2022-2024 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/)
+#
+# 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.
+
diff --git a/src/telemetry/backend/requirements.in b/src/telemetry/backend/requirements.in
index 2843bdbf68defcc1a972b49bfa12a8107b696aaa..603c6e4b58629fbeb241f316d5e3b564e38a0462 100644
--- a/src/telemetry/backend/requirements.in
+++ b/src/telemetry/backend/requirements.in
@@ -14,5 +14,7 @@
 
 anytree==2.8.0
 confluent-kafka==2.3.*
+libyang==2.8.4
 numpy==2.0.1
 APScheduler==3.10.1
+pygnmi==0.8.14
diff --git a/src/telemetry/backend/tests/test_backend.py b/src/telemetry/backend/tests/test_backend.py
index e75b33ca58c6bf27c5d2e1c2012dc31de5274ad3..3dffab8a4ed2102604c5d9d87f87923ddb051247 100644
--- a/src/telemetry/backend/tests/test_backend.py
+++ b/src/telemetry/backend/tests/test_backend.py
@@ -17,7 +17,15 @@ import time
 from typing import Dict
 from common.tools.kafka.Variables import KafkaTopic
 from telemetry.backend.service.TelemetryBackendService import TelemetryBackendService
-from .messages import create_collector_request
+from .messages import create_collector_request, _create_kpi_descriptor, _create_kpi_id
+from .Fixtures import context_client, device_client, service_client, kpi_manager_client
+from .add_devices import load_topology
+from common.tools.context_queries.Topology import get_topology
+from common.Constants import DEFAULT_CONTEXT_NAME
+from common.tools.context_queries.Device import get_device, add_device_to_topology
+# from common.tools.context_queries.EndPoint import get_endpoint_names
+from common.proto.context_pb2 import EndPointId, DeviceId, TopologyId, ContextId , Empty
+from common.proto.kpi_manager_pb2 import KpiId
 
 LOGGER = logging.getLogger(__name__)
 
diff --git a/src/telemetry/backend/tests/test_gnmi_collector.py b/src/telemetry/backend/tests/test_gnmi_collector.py
new file mode 100644
index 0000000000000000000000000000000000000000..3c7a6a85a104a2b1bcd8b8d82bb469c63adfbec9
--- /dev/null
+++ b/src/telemetry/backend/tests/test_gnmi_collector.py
@@ -0,0 +1,50 @@
+# Copyright 2022-2024 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/)
+#
+# 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.
+
+import pytest
+import logging
+from unittest.mock import patch, MagicMock
+from src.telemetry.backend.collectors.gnmi_openconfig.GnmiOpenConfigCollector import GnmiOpenConfigCollector
+
+LOGGER = logging.getLogger(__name__)
+LOGGER.setLevel(logging.DEBUG)
+
+@pytest.fixture(autouse=True)
+def log_all_methods(request):
+    LOGGER.info(f" >>>>> Starting test: {request.node.name} ")
+    yield
+    LOGGER.info(f" <<<<< Finished test: {request.node.name} ")
+
+@pytest.fixture()
+def gnmi_openconfig_driver():
+    collector = GnmiOpenConfigCollector(
+        "192.168.1.1", 
+        57400, 
+        secure   = True,
+        username = "admin",
+        password = "secret",
+        use_tls  = False
+    )
+    LOGGER.info("Yielding GnmiOpenConfigCollector collector instance ...")
+    yield collector
+    LOGGER.info("Terminating GnmiOpenConfigCollector collector instance ...")
+
+# def test_init(gnmi_openconfig_driver):
+#     # Test initializing the driver with all parameters
+#     driver = gnmi_openconfig_driver
+#     assert driver.address == "192.168.1.1"
+#     assert driver.port    == 57400
+
+
+