Adds support for BBF WT-385 xPON model:

VOL-151: Framework for OLT PON Configuration Parameters
VOL-152: Framework for ONU Configuration Parameters
VOL-220: Support configuration(Create/Read/Delete) of Channel-Group,
         Channel-Partition, Channel-Pair & Channel-Termination Objects
         for XGS-PON

Change-Id: I992a4e03e6e7b021d7aa9a49a5f8466876c8f07c
diff --git a/cli/main.py b/cli/main.py
index 327f122..a05041a 100755
--- a/cli/main.py
+++ b/cli/main.py
@@ -29,6 +29,7 @@
 from simplejson import dumps
 
 from cli.device import DeviceCli
+from cli.xpon import XponCli
 from cli.alarm_filters import AlarmFiltersCli
 from cli.logical_device import LogicalDeviceCli
 from cli.table import print_pb_list_as_table
@@ -241,6 +242,15 @@
                            if d.startswith(text)]
         return completions
 
+    def do_xpon(self, line):
+        """xpon <optional> [device_ID] - Enter xpon level command mode"""
+        device_id = line.strip()
+        if not device_id:
+            sub = XponCli(self.get_channel, "")
+        else:
+            sub = XponCli(self.get_channel, device_id)
+        sub.cmdloop()
+
     def do_pdb(self, line):
         """Launch PDB debug prompt in CLI (for CLI development)"""
         from pdb import set_trace
diff --git a/cli/xpon.py b/cli/xpon.py
new file mode 100644
index 0000000..61b235b
--- /dev/null
+++ b/cli/xpon.py
@@ -0,0 +1,1157 @@
+#!/usr/bin/env python
+#
+# Copyright 2016 the original author or authors.
+#
+# 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.
+#
+
+"""
+XPon level CLI commands
+"""
+from optparse import make_option
+from cmd2 import Cmd, options
+from simplejson import dumps
+
+from google.protobuf.empty_pb2 import Empty
+from cli.table import print_pb_as_table, print_pb_list_as_table
+from cli.utils import print_flows, pb2dict
+from voltha.protos import third_party
+from voltha.protos.bbf_fiber_base_pb2 import \
+    AllChannelgroupConfig, ChannelgroupConfig, \
+    AllChannelpairConfig, ChannelpairConfig, \
+    AllChannelpartitionConfig, ChannelpartitionConfig, \
+    AllChannelterminationConfig, ChannelterminationConfig, \
+    AllOntaniConfig, OntaniConfig, AllVOntaniConfig , \
+    VOntaniConfig, AllVEnetConfig , VEnetConfig
+
+_ = third_party
+from voltha.protos import voltha_pb2, bbf_fiber_types_pb2, ietf_interfaces_pb2
+import sys
+from google.protobuf.json_format import MessageToDict
+
+# Since proto3 won't send fields that are set to 0/false/"" any object that
+# might have those values set in them needs to be replicated here such that the
+# fields can be adequately
+
+class XponCli(Cmd):
+
+    def __init__(self, get_channel, device_id):
+        Cmd.__init__(self)
+        self.get_channel = get_channel
+        self.device_id = device_id
+        self.prompt = '(' + self.colorize(
+            self.colorize('voltha-xpon {}'.format(device_id), 'green'), 'bold') + ') '
+
+    def cmdloop(self):
+        self._cmdloop()
+
+    def get_interface_based_on_device(self):
+        stub = voltha_pb2.VolthaLocalServiceStub(self.get_channel())
+        temp_list = []
+        cg_list = []
+        cpart_list = []
+        cp_list = []
+        vont_list = []
+        ont_list = []
+        v_enet_list = []
+        ct = stub.GetAllChannelterminationConfig(voltha_pb2.ID(id=self.device_id))
+        cps = stub.GetAllChannelpairConfig(Empty()).channelpair_config
+        cparts = stub.GetAllChannelpartitionConfig(Empty()).channelpartition_config
+        cgs = stub.GetAllChannelgroupConfig(Empty()).channelgroup_config
+        onts = stub.GetAllOntaniConfig(Empty()).ontani_config
+        vonts = stub.GetAllVOntaniConfig(Empty()).v_ontani_config
+        venets = stub.GetAllVEnetConfig(Empty()).v_enet_config
+
+        for cterm in ct.channeltermination_config:
+            temp_list.append(cterm.data.channelpair_ref)
+        for cp in cps:
+            if cp.name in temp_list:
+                cp_list.append(cp)
+        temp_list = []
+
+        for cp in cp_list:
+            temp_list.append(cp.data.channelpartition_ref)
+        for cpart in cparts:
+            if cpart.name in temp_list:
+                cpart_list.append(cpart)
+        temp_list = []
+
+        for cpart in cpart_list:
+            temp_list.append(cpart.data.channelgroup_ref)
+        for cg in cgs:
+            if cg.name in temp_list:
+                cg_list.append(cg)
+        temp_list = []
+
+        for vont in vonts:
+            if vont.data.parent_ref in cpart_list or \
+                vont.data.preferred_chanpair in cp_list:
+                vont_list.append(vont)
+
+        for ont in onts:
+            if ont.name in vont_list:
+                ont_list.append(ont)
+                temp_list.append(ont.name)
+
+        for venet in venets:
+            if venet.data.v_ontani_ref in temp_list:
+                v_enet_list.append(venet)
+        temp_list = []
+
+        return cg_list, cpart_list, cp_list, ct.channeltermination_config, vont_list, ont_list, v_enet_list
+
+    do_exit = Cmd.do_quit
+
+    def do_quit(self, line):
+        return self._STOP_AND_EXIT
+
+    def do_show(self, line):
+        """Show detailed information of each interface based on device ID or all interfaces"""
+        stub = voltha_pb2.VolthaLocalServiceStub(self.get_channel())
+        if line.strip():
+            self.device_id = line.strip()
+        if self.device_id:
+            cg, cpart, cp, ct, vont, ont, venet = self.get_interface_based_on_device()
+            print_pb_list_as_table("Channel Groups for device ID = {}:".format(self.device_id),
+                                   cg, {}, self.poutput)
+            print_pb_list_as_table("Channel Partitions for device ID = {}:".format(self.device_id),
+                                   cpart, {}, self.poutput)
+            print_pb_list_as_table("Channel Pairs: for device ID = {}:".format(self.device_id),
+                                   cp, {}, self.poutput)
+            print_pb_list_as_table("Channel Terminations for device ID = {}:".format(self.device_id),
+                                   ct, {}, self.poutput)
+            print_pb_list_as_table("VOnt Anis for device ID = {}:".format(self.device_id),
+                                   vont, {}, self.poutput)
+            print_pb_list_as_table("Ont Anis for device ID = {}:".format(self.device_id),
+                                   ont, {}, self.poutput)
+            print_pb_list_as_table("VEnets for device ID = {}:".format(self.device_id),
+                                   venet, {}, self.poutput)
+        else:
+            interface = stub.GetAllChannelgroupConfig(Empty())
+            print_pb_list_as_table("Channel Groups:",
+                                   interface.channelgroup_config,
+                                   {}, self.poutput)
+            interface = stub.GetAllChannelpartitionConfig(Empty())
+            print_pb_list_as_table("Channel Partitions:",
+                                   interface.channelpartition_config,
+                                   {}, self.poutput)
+            interface = stub.GetAllChannelpairConfig(Empty())
+            print_pb_list_as_table("Channel Pairs:",
+                                   interface.channelpair_config,
+                                   {}, self.poutput)
+            devices = stub.ListDevices(Empty())
+            for d in devices.items:
+                interface = stub.GetAllChannelterminationConfig(voltha_pb2.ID(id=d.id))
+                print_pb_list_as_table("Channel Terminations for device ID = {}:".format(d.id),
+                                   interface.channeltermination_config,
+                                   {}, self.poutput)
+            interface = stub.GetAllVOntaniConfig(Empty())
+            print_pb_list_as_table("VOnt Anis:",
+                                   interface.v_ontani_config,
+                                   {}, self.poutput)
+            interface = stub.GetAllOntaniConfig(Empty())
+            print_pb_list_as_table("Ont Anis:",
+                                   interface.ontani_config,
+                                   {}, self.poutput)
+            interface = stub.GetAllVEnetConfig(Empty())
+            print_pb_list_as_table("VEnets:",
+                                   interface.v_enet_config,
+                                   {}, self.poutput)
+
+    def help_channel_group(self):
+        self.poutput(
+'''
+channel_group [get | create | update | delete] [-n <name>] [-d <description>] [-a <admin state>]
+              [-l <link up down trap enable type>] [-p <polling period>] [-s <system id>]
+              [-r <raman mitigation>]
+
+get:    displays existing channel groups
+        Required flags: None
+create: creates channel group with the parameters specified with -n, -d, -a, -l, -p, -s and -r.
+        Required flags: <name>
+update: updates existing channel group specified with parameter -n by changing its parameter values 
+        specified with -d, -a, -l, -p, -s and -r.
+        Required flags: <name>
+delete: deletes channel group specified with parameter -n.
+        Required flags: <name>
+
+-n: <string> name of channel group.
+-d: <string> description of channel group.
+-a: <string> admin state of channel group.
+-l: <enum>   link up down trap enable type. 
+-p: <int>    polling period for channel group.
+-s: <string> system id for channel group.
+-r: <enum>   raman mitigation for channel group.
+
+Example:
+
+channel_group create -n cg-1 -a up -p 100 -s 000000 -r raman_none
+'''
+        )
+
+    @options([
+        make_option('-n', '--name', action="store", dest='name', type='string',
+                    help='name of channel group', default=None),
+        make_option('-d', '--description', action="store", dest='description',
+                    type='string', help='description of channel group', default=None),
+        make_option('-a', '--admin_state', action="store", dest='enabled', type='string',
+                    help='admin state of channel group', default=None),
+        make_option('-l', '--trap', action="store", dest='link_up_down_trap_enable',
+                    type='string', help='link up down trap enable type', default=None),
+        make_option('-p', '--pp', action='store', dest='polling_period',
+                    type='int', help='polling period of channel group', default=None),
+        make_option('-s', '--sid', action='store', dest='system_id',
+                    type='string', help='system id of channel group', default=None),
+        make_option('-r', '--rm', action='store', dest='raman_mitigation',
+                    type='string', help='raman mitigation of channel group', default=None),
+    ])
+
+    def do_channel_group(self, line, opts):
+        """channel group get, create -flags <attributes>, update -flags <attributes>, delete -n <name>"""
+        # Ensure that a valid sub-command was provided
+        if line.strip() not in {"get", "create", "update", "delete"}:
+            self.poutput(self.colorize('Error: ', 'red') + \
+                        self.colorize(self.colorize(line.strip(), 'blue'),
+                                      'bold') + ' is not recognized')
+            return
+
+        stub = voltha_pb2.VolthaLocalServiceStub(self.get_channel())
+
+        if line.strip() == "get":
+            if self.device_id:
+                cg, cpart, cp, ct, vont, ont, venet = self.get_interface_based_on_device()
+                print_pb_list_as_table("Channel Groups for device ID = {}:".format(self.device_id),
+                                       cg, {}, self.poutput)
+            else:
+                interface = stub.GetAllChannelgroupConfig(Empty())
+                print_pb_list_as_table("Channel Groups:",
+                                       interface.channelgroup_config,
+                                       {}, self.poutput)
+            return
+        #if not opts.name:
+        #    self.poutput(self.colorize('Error: ', 'red') + \
+        #                self.colorize(self.colorize('Name is required parameter', 'blue'),
+        #                              'bold'))
+        #    return
+        #if interface_instance:
+        #    self.poutput(self.colorize('Unable. Please commit or reset: ', 'yellow') + \
+        #                self.colorize(interface_instance.name, 'blue'))
+        #    return
+        interface_instance = ChannelgroupConfig(name = opts.name)
+        interface_instance.interface.name = opts.name
+        if opts.description:
+            interface_instance.interface.description = opts.description
+        interface_instance.interface.type = "channelgroup"
+        if opts.enabled:
+            if opts.enabled == "up":
+                interface_instance.interface.enabled = True
+            elif opts.enabled == "down":
+                interface_instance.interface.enabled = False
+            else:
+                self.poutput(self.colorize('Error: ', 'red') + \
+                            self.colorize(self.colorize('Invalid admin state parameter for channel group', 'blue'),
+                                          'bold'))
+                return
+        if opts.link_up_down_trap_enable:
+            types = ["trap_disabled", "trap_enabled"]
+            try:
+                assert opts.link_up_down_trap_enable in types, \
+                        'Invalid Enum value for Channel Group link up down trap enable type \'{}\''\
+                        .format(opts.link_up_down_trap_enable)
+                interface_instance.interface.link_up_down_trap_enable = \
+                    ietf_interfaces_pb2._INTERFACE_LINKUPDOWNTRAPENABLETYPE.values_by_name[opts.link_up_down_trap_enable.upper()].number
+            except AssertionError, e:
+                self.poutput(self.colorize('Error: ', 'red') + \
+                            self.colorize(self.colorize(e.message, 'blue'),
+                                          'bold'))
+                return
+
+        if opts.polling_period:
+            interface_instance.data.polling_period = opts.polling_period
+        if opts.raman_mitigation:
+            raman_mitigations = ["raman_none", "raman_miller", "raman_8b10b"]
+            try:
+                assert opts.raman_mitigation in raman_mitigations, \
+                        'Invalid Enum value for Channel Group raman mitigation \'{}\''.format(opts.raman_mitigation)
+                interface_instance.data.raman_mitigation = \
+                    bbf_fiber_types_pb2._RAMANMITIGATIONTYPE.values_by_name[opts.raman_mitigation.upper()].number
+            except AssertionError, e:
+                self.poutput(self.colorize('Error: ', 'red') + \
+                            self.colorize(self.colorize(e.message, 'blue'),
+                                          'bold'))
+                return
+        if opts.system_id:
+            interface_instance.data.system_id = opts.system_id
+
+        if line.strip() == "create":
+            stub.CreateChannelgroup(interface_instance)
+        elif line.strip() == "update":
+            stub.UpdateChannelgroup(interface_instance)
+        elif line.strip() == "delete":
+            stub.DeleteChannelgroup(interface_instance)
+        return
+
+    def help_channel_partition(self):
+        self.poutput(
+'''
+channel_partition  [get | create | update | delete] [-n <name>] [-d <description>] [-a <admin state>]
+                   [-l <link up down trap enable type>] [-r <differential fiber distance>]
+                   [-o <closest ont distance>] [-f <fec downstream>] [-m <multicast aes indicator>]
+                   [-u <authentication method>] [-c <channel group reference>]
+
+get:    displays existing channel partitions
+        Required flags: None
+create: creates channel partition with the parameters specified with -n, -d, -a, -l, -r, -o, -f, -m, -u and -c.
+        Required flags: <name>, <channel group reference>
+update: updates existing channel partition specified with parameter -n by changing its parameter values
+        specified with -d, -a, -l, -r, -o, -f, -m, -u and -c.
+        Required flags: <name>
+delete: deletes channel group specified with parameter -n.
+        Required flags: <name>
+
+-n: <string> name of channel partition.
+-d: <string> description of channel partition.
+-a: <string> admin state of channel partition.
+-l: <enum>   link up down trap enable type.
+-r: <int>    differential fiber distance.
+-o: <int>    closest ont distance.
+-f: <bool>   forward and error correction downstream.
+-m: <bool>   multicast aes indicator of channel partition.
+-u: <enum>   authentication method.
+-c: <string> channel group reference for this channel partition.
+
+Example:
+
+channel_partition create -n cpart-1-1 -a up -r 20 -o 0 -f false -m false -u serial_number -c cg-1
+'''
+        )
+
+    @options([
+        make_option('-n', '--name', action="store", dest='name', type='string',
+                    help='name of channel partition', default=None),
+        make_option('-d', '--description', action="store", dest='description',
+                    type='string', help='description of channel partition', default=None),
+        make_option('-a', '--admin_state', action="store", dest='enabled', type='string',
+                    help='admin state of channel partition', default=None),
+        make_option('-l', '--trap', action="store", dest='link_up_down_trap_enable',
+                    type='string', help='link up down trap enable type', default=None),
+        make_option('-r', '--diff_fib_dist', action='store', dest='differential_fiber_distance',
+                    type='int', help='differential fiber distance', default=None),
+        make_option('-o', '--ont_dist', action='store', dest='closest_ont_distance',
+                    type='int', help='closest ont distance', default=None),
+        make_option('-f', '--fec_ds', action='store', dest='fec_downstream',
+                    type='string', help='forward and error correction downstream', default=None),
+        make_option('-m', '--mc_aes', action='store', dest='multicast_aes_indicator',
+                    type='string', help='multicast aes indicator of channel partition', default=None),
+        make_option('-u', '--auth', action='store', dest='authentication_method',
+                    type='string', help='authentication method', default=None),
+        make_option('-c', '--cg_ref', action='store', dest='channelgroup_ref',
+                    type='string', help='channel group reference for this channel partition', default=None),
+    ])
+
+    def do_channel_partition(self, line, opts):
+        """channel partition get, create -flags <attributes>, update -flags <attributes>, delete -n <name>"""
+        # Ensure that a valid sub-command was provided
+        if line.strip() not in {"get", "create", "update", "delete"}:
+            self.poutput(self.colorize('Error: ', 'red') + \
+                        self.colorize(self.colorize(line.strip(), 'blue'),
+                                      'bold') + ' is not recognized')
+            return
+
+        stub = voltha_pb2.VolthaLocalServiceStub(self.get_channel())
+
+        if line.strip() == "get":
+            if self.device_id:
+                cg, cpart, cp, ct, vont, ont, venet = self.get_interface_based_on_device()
+                print_pb_list_as_table("Channel Partitions for device ID = {}:".format(self.device_id),
+                                       cpart, {}, self.poutput)
+            else:
+                interface = stub.GetAllChannelpartitionConfig(Empty())
+                print_pb_list_as_table("Channel Partitions:",
+                                       interface.channelpartition_config,
+                                       {}, self.poutput)
+            return
+
+        interface_instance = ChannelpartitionConfig(name = opts.name)
+        interface_instance.interface.name = opts.name
+        if opts.description:
+            interface_instance.interface.description = opts.description
+        interface_instance.interface.type = "channelpartition"
+        if opts.enabled:
+            if opts.enabled == "up":
+                interface_instance.interface.enabled = True
+            elif opts.enabled == "down":
+                interface_instance.interface.enabled = False
+            else:
+                self.poutput(self.colorize('Error: ', 'red') + \
+                            self.colorize(self.colorize('Invalid admin state parameter for channel partition', 'blue'),
+                                          'bold'))
+                return
+        if opts.link_up_down_trap_enable:
+            types = ["trap_disabled", "trap_enabled"]
+            try:
+                assert opts.link_up_down_trap_enable in types, \
+                        'Invalid Enum value for Channel Partition link up down trap enable type \'{}\''\
+                        .format(opts.link_up_down_trap_enable)
+                interface_instance.interface.link_up_down_trap_enable = \
+                    ietf_interfaces_pb2._INTERFACE_LINKUPDOWNTRAPENABLETYPE.values_by_name[opts.link_up_down_trap_enable.upper()].number
+            except AssertionError, e:
+                self.poutput(self.colorize('Error: ', 'red') + \
+                            self.colorize(self.colorize(e.message, 'blue'),
+                                          'bold'))
+                return
+
+        if opts.differential_fiber_distance:
+            interface_instance.data.differential_fiber_distance = opts.differential_fiber_distance
+        if opts.closest_ont_distance:
+            interface_instance.data.closest_ont_distance = opts.closest_ont_distance
+        if opts.fec_downstream:
+            if opts.fec_downstream == 'true':
+                interface_instance.data.fec_downstream = True
+            elif opts.fec_downstream == 'false':
+                interface_instance.data.fec_downstream = False
+            else:
+                m = 'Invalid boolean value for Channel Partition fec_downstream \'{}\''\
+                    .format(opts.fec_downstream)
+                self.poutput(self.colorize('Error: ', 'red') + \
+                            self.colorize(self.colorize(m, 'blue'),
+                                          'bold'))
+                return
+        if opts.multicast_aes_indicator:
+            if opts.multicast_aes_indicator == 'true':
+                interface_instance.data.multicast_aes_indicator = True
+            elif opts.multicast_aes_indicator == 'false':
+                interface_instance.data.multicast_aes_indicator = False
+            else:
+                m = 'Invalid boolean value for Channel Partition multicast_aes_indicator \'{}\''\
+                    .format(opts.multicast_aes_indicator)
+                self.poutput(self.colorize('Error: ', 'red') + \
+                            self.colorize(self.colorize(m, 'blue'),
+                                          'bold'))
+                return
+        if opts.authentication_method:
+            auth_method_types = ["serial_number", "loid", "registration_id", "omci", "dot1x"]
+            try:
+                assert opts.authentication_method in auth_method_types, \
+                        'Invalid Enum value for Channel Partition authentication method \'{}\''.format(opts.authentication_method)
+                interface_instance.data.authentication_method = \
+                    bbf_fiber_types_pb2._AUTHMETHODTYPE.values_by_name[opts.authentication_method.upper()].number
+            except AssertionError, e:
+                self.poutput(self.colorize('Error: ', 'red') + \
+                            self.colorize(self.colorize(e.message, 'blue'),
+                                          'bold'))
+                return
+        if opts.channelgroup_ref:
+            interface_instance.data.channelgroup_ref = opts.channelgroup_ref
+
+        if line.strip() == "create":
+            stub.CreateChannelpartition(interface_instance)
+        elif line.strip() == "update":
+            stub.UpdateChannelpartition(interface_instance)
+        elif line.strip() == "delete":
+            stub.DeleteChannelpartition(interface_instance)
+        return
+
+    def help_channel_pair(self):
+        self.poutput(
+'''
+channel_pair [get | create | update | delete] [-n <name>] [-d <description>] [-a <admin state>]
+             [-l <link up down trap enable type>] [-r <channel pair line rate>]
+             [-t <channel pair type>] [-g <channel group reference>] [-i <gpon pon id interval>]
+             [-p <channel partition reference>] [-o <gpon pon id odn class>]
+
+get:    displays existing channel pairs
+        Required flags: None
+create: creates channel pair with the parameters specified with -n, -d, -a, -l, -r, -t, -g, -i, -p and -o.
+        Required flags: <name>, <channel pair type>
+update: updates existing channel pair specified with parameter -n by changing its parameter values
+        specified with -d, -a, -l, -r, -t, -g, -i, -p and -o.
+        Required flags: <name>
+delete: deletes channel group specified with parameter -n.
+        Required flags: <name>
+
+-n: <string> name of channel pair.
+-d: <string> description of channel pair.
+-a: <string> admin state of channel pair.
+-l: <enum>   link up down trap enable type.
+-r: <string> channel pair line rate.
+-t: <string> channel pair type.
+-g: <string> channel group reference.
+-i: <int>    gpon pon id interval.
+-p: <string> channel partition reference.
+-o: <enum>   gpon pon id odn class.
+
+Example:
+
+channel_pair create -n cp-1 -a up -r unplanned_cp_speed -t channelpair -g cg-1 -i 0 -p cpart-1-1 -o class_a
+'''
+        )
+
+    @options([
+        make_option('-n', '--name', action="store", dest='name', type='string',
+                    help='name of channel pair', default=None),
+        make_option('-d', '--description', action="store", dest='description',
+                    type='string', help='description of channel pair', default=None),
+        make_option('-a', '--admin_state', action="store", dest='enabled', type='string',
+                    help='admin state of channel pair', default=None),
+        make_option('-l', '--trap', action="store", dest='link_up_down_trap_enable',
+                    type='string', help='link up down trap enable type', default=None),
+        make_option('-r', '--cp_line_rate', action='store', dest='channelpair_linerate',
+                    type='string', help='channel pair linerate', default=None),
+        make_option('-t', '--cp_type', action='store', dest='channelpair_type',
+                    type='string', help='channel pair type', default=None),
+        make_option('-g', '--cg_ref', action='store', dest='channelgroup_ref',
+                    type='string', help='channel group reference', default=None),
+        make_option('-i', '--interval', action='store', dest='gpon_ponid_interval',
+                    type='int', help='gpon pon id interval', default=None),
+        make_option('-p', '--cpart_ref', action='store', dest='channelpartition_ref',
+                    type='string', help='channel partition reference', default=None),
+        make_option('-o', '--odn_class', action='store', dest='gpon_ponid_odn_class',
+                    type='string', help='gpon pon id odn class', default=None),
+    ])
+
+    def do_channel_pair(self, line, opts):
+        """channel pair get, create -flags <attributes>, update -flags <attributes>, delete -n <name>"""
+        # Ensure that a valid sub-command was provided
+        if line.strip() not in {"get", "create", "update", "delete"}:
+            self.poutput(self.colorize('Error: ', 'red') + \
+                        self.colorize(self.colorize(line.strip(), 'blue'),
+                                      'bold') + ' is not recognized')
+            return
+
+        stub = voltha_pb2.VolthaLocalServiceStub(self.get_channel())
+
+        if line.strip() == "get":
+            if self.device_id:
+                cg, cpart, cp, ct, vont, ont, venet = self.get_interface_based_on_device()
+                print_pb_list_as_table("Channel Pairs for device ID = {}:".format(self.device_id),
+                                       cp, {}, self.poutput)
+            else:
+                interface = stub.GetAllChannelpairConfig(Empty())
+                print_pb_list_as_table("Channel Pairs:",
+                                       interface.channelpair_config,
+                                       {}, self.poutput)
+            return
+
+        interface_instance = ChannelpairConfig(name = opts.name)
+        interface_instance.interface.name = opts.name
+        if opts.description:
+            interface_instance.interface.description = opts.description
+        interface_instance.interface.type = "channelpair"
+        if opts.enabled:
+            if opts.enabled == "up":
+                interface_instance.interface.enabled = True
+            elif opts.enabled == "down":
+                interface_instance.interface.enabled = False
+            else:
+                self.poutput(self.colorize('Error: ', 'red') + \
+                            self.colorize(self.colorize('Invalid admin state parameter for channel pair', 'blue'),
+                                          'bold'))
+                return
+        if opts.link_up_down_trap_enable:
+            types = ["trap_disabled", "trap_enabled"]
+            try:
+                assert opts.link_up_down_trap_enable in types, \
+                        'Invalid Enum value for Channel Pair link up down trap enable type \'{}\''\
+                        .format(opts.link_up_down_trap_enable)
+                interface_instance.interface.link_up_down_trap_enable = \
+                    ietf_interfaces_pb2._INTERFACE_LINKUPDOWNTRAPENABLETYPE.values_by_name[opts.link_up_down_trap_enable.upper()].number
+            except AssertionError, e:
+                self.poutput(self.colorize('Error: ', 'red') + \
+                            self.colorize(self.colorize(e.message, 'blue'),
+                                          'bold'))
+                return
+
+        if opts.channelpair_linerate:
+            interface_instance.data.channelpair_linerate = opts.channelpair_linerate
+        if opts.channelpair_type:
+            interface_instance.data.channelpair_type = opts.channelpair_type
+        if opts.channelgroup_ref:
+            interface_instance.data.channelgroup_ref = opts.channelgroup_ref
+        if opts.gpon_ponid_interval:
+            interface_instance.data.gpon_ponid_interval = opts.gpon_ponid_interval
+        if opts.channelpartition_ref:
+            interface_instance.data.channelpartition_ref = opts.channelpartition_ref
+        if opts.gpon_ponid_odn_class:
+            class_types = ["class_a", "class_b", "class_b_plus", "class_c", "class_c_plus", "class_auto"]
+            try:
+                assert opts.gpon_ponid_odn_class in class_types, \
+                        'Invalid enum value for Channel Pair gpon pon id odn class \'{}\''.format(opts.gpon_ponid_odn_class)
+                interface_instance.data.gpon_ponid_odn_class = \
+                    bbf_fiber_types_pb2._PONIDODNCLASSTYPE.values_by_name[opts.gpon_ponid_odn_class.upper()].number
+            except AssertionError, e:
+                self.poutput(self.colorize('Error: ', 'red') + \
+                            self.colorize(self.colorize(e.message, 'blue'),
+                                          'bold'))
+                return
+
+        if line.strip() == "create":
+            stub.CreateChannelpair(interface_instance)
+        elif line.strip() == "update":
+            stub.UpdateChannelpair(interface_instance)
+        elif line.strip() == "delete":
+            stub.DeleteChannelpair(interface_instance)
+        return
+
+    def help_channel_termination(self):
+        self.poutput(
+'''
+channel_termination [get | create | update | delete] [-i <id>] [-n <name>]
+                    [-d <description>] [-a <admin state>] [-l <link up down trap enable type>]
+                    [-r <channel pair reference>] [-m <meant for type_b primary role>]
+                    [-w <ngpon2 time wavelength division multiplexing admin label>]
+                    [-p <ngpon2 ptp admin label>] [-s <xgs pon id>]
+                    [-x <xgpon pon id>] [-g <gpon pon id>] [-t <pon tag>]
+                    [-b <ber calc period>] [-l <location>] [-u <url to reach>]
+
+get:    displays existing channel pairs
+        Required flags: None
+create: creates channel pair with the parameters specified with -i -n, -d, -a, -l, -r, -m, -w, -p, -s, -x, -g, -t, -b, -c and -u
+        Required flags: <id>, <name>
+update: updates existing channel termination specified with -i and -n parameters by changing
+        its parameter values specified with -d, -a, -l, -r, -m, -w, -p, -s, -x, -g, -b, -c, and -u
+        Required flags: <id>, <name>
+delete: deletes channel termination specified with parameter -i and -n.
+        Required flags: <id>, <name>
+
+-i: <string> device id.
+-n: <string> name of channel termination.
+-d: <string> description of channel termination.
+-a: <string> admin state of channel termination.
+-l: <enum>   link up down trap enable type.
+-r: <string> channel pair reference for this channel termination.
+-m: <bool>   meant for type_b primary role.
+-w: <int>    ngpon2 time wavelength division multiplexing admin label.
+-p: <int>    ngpon2 precision time protocol admin label.
+-s: <int>    xgs pon id.
+-x: <int>    xgpon pon id.
+-g: <string> gpon pon id.
+-t: <string> pon tag.
+-b: <int>    bit error rate calculation period.
+-c: <string> location of channel termination.
+-u: <string> url to reach channel termination.
+
+Example:
+
+channel_termination create -i f90bb953f988 -n cterm-1 -a up -r cp-1 -m false -w 0 -p 0 -s 0 -x 0 -b 0 -c raleigh -u localhost
+
+'''
+        )
+
+    @options([
+        make_option('-i', '--id', action="store", dest='id', type='string',
+                    help='device id', default=None),
+        make_option('-n', '--name', action="store", dest='name', type='string',
+                    help='name of channel pair', default=None),
+        make_option('-d', '--description', action="store", dest='description',
+                    type='string', help='description of channel termination', default=None),
+        make_option('-a', '--admin_state', action="store", dest='enabled', type='string',
+                    help='admin state of channel termination', default=None),
+        make_option('-l', '--trap', action="store", dest='link_up_down_trap_enable',
+                    type='string', help='link up down trap enable type', default=None),
+        make_option('-r', '--cp_ref', action='store', dest='channelpair_ref',
+                    type='string', help='channel pair reference for this channel termination', default=None),
+        make_option('-m', '--type_b', action='store', dest='meant_for_type_b_primary_role',
+                    type='string', help='meant for type_b primary role', default=None),
+        make_option('-w', '--t_w_d_m', action='store', dest='ngpon2_twdm_admin_label',
+                    type='int', help='ngpon2 time wavelength division multiplexing admin label', default=None),
+        make_option('-p', '--ptp', action='store', dest='ngpon2_ptp_admin_label',
+                    type='int', help='ngpon2 precision time protocol admin label', default=None),
+        make_option('-s', '--xgs', action='store', dest='xgs_ponid',
+                    type='int', help='xgs pon id', default=None),
+        make_option('-x', '--xgpon', action='store', dest='xgpon_ponid',
+                    type='int', help='xgpon pon id', default=None),
+        make_option('-g', '--gpon_pon', action='store', dest='gpon_ponid',
+                    type='string', help='gpon pon id', default=None),
+        make_option('-t', '--pon', action='store', dest='pon_tag',
+                    type='string', help='pon tag', default=None),
+        make_option('-b', '--ber', action='store', dest='ber_calc_period',
+                    type='int', help='bit error rate calculation period', default=None),
+        make_option('-c', '--location', action='store', dest='location',
+                    type='string', help='location of channel termination', default=None),
+        make_option('-u', '--url', action='store', dest='url_to_reach',
+                    type='string', help='url to reach channel termination', default=None),
+    ])
+
+    def do_channel_termination(self, line, opts):
+        """channel termination get, create -flags <attributes>, update -flags <attributes>, delete -i <id> -n <name>"""
+        # Ensure that a valid sub-command was provided
+        if line.strip() not in {"get", "create", "update", "delete"}:
+            self.poutput(self.colorize('Error: ', 'red') + \
+                        self.colorize(self.colorize(line.strip(), 'blue'),
+                                      'bold') + ' is not recognized')
+            return
+
+        stub = voltha_pb2.VolthaLocalServiceStub(self.get_channel())
+
+        if line.strip() == "get":
+            if self.device_id:
+                cg, cpart, cp, ct, vont, ont, venet = self.get_interface_based_on_device()
+                print_pb_list_as_table("Channel Terminations for device ID = {}:".format(self.device_id),
+                                       ct, {}, self.poutput)
+            elif opts.id:
+                ct = stub.GetAllChannelterminationConfig(voltha_pb2.ID(id=opts.id)).channeltermination_config
+                print_pb_list_as_table("Channel Terminations for device ID = {}:".format(opts.id),
+                                       ct, {}, self.poutput)
+            else:
+                devices = stub.ListDevices(Empty())
+                for d in devices.items:
+                    interface = stub.GetAllChannelterminationConfig(voltha_pb2.ID(id=d.id))
+                    print_pb_list_as_table("Channel Terminations for device ID = {}:".format(d.id),
+                                       interface.channeltermination_config,
+                                       {}, self.poutput)
+            return
+
+        interface_instance = ChannelterminationConfig(id = opts.id, name = opts.name)
+        interface_instance.interface.name = opts.name
+        if opts.description:
+            interface_instance.interface.description = opts.description
+        interface_instance.interface.type = "channel-termination"
+        if opts.enabled:
+            if opts.enabled == "up":
+                interface_instance.interface.enabled = True
+            elif opts.enabled == "down":
+                interface_instance.interface.enabled = False
+            else:
+                self.poutput(self.colorize('Error: ', 'red') + \
+                            self.colorize(self.colorize('Invalid admin state parameter for channel termination', 'blue'),
+                                          'bold'))
+                return
+        if opts.link_up_down_trap_enable:
+            types = ["trap_disabled", "trap_enabled"]
+            try:
+                assert opts.link_up_down_trap_enable in types, \
+                        'Invalid Enum value for Channel Termination link up down trap enable type \'{}\''\
+                        .format(opts.link_up_down_trap_enable)
+                interface_instance.interface.link_up_down_trap_enable = \
+                    ietf_interfaces_pb2._INTERFACE_LINKUPDOWNTRAPENABLETYPE.values_by_name[opts.link_up_down_trap_enable.upper()].number
+            except AssertionError, e:
+                self.poutput(self.colorize('Error: ', 'red') + \
+                            self.colorize(self.colorize(e.message, 'blue'),
+                                          'bold'))
+                return
+
+        if opts.channelpair_ref:
+            interface_instance.data.channelpair_ref = opts.channelpair_ref
+        if opts.meant_for_type_b_primary_role:
+            if opts.meant_for_type_b_primary_role == 'true':
+                interface_instance.data.meant_for_type_b_primary_role = True
+            elif opts.meant_for_type_b_primary_role == 'false':
+                interface_instance.data.meant_for_type_b_primary_role = False
+            else:
+                m = 'Invalid boolean value for Channel Termination meant_for_type_b_primary_role \'{}\''\
+                    .format(opts.meant_for_type_b_primary_role)
+                self.poutput(self.colorize('Error: ', 'red') + \
+                            self.colorize(self.colorize(m, 'blue'),
+                                          'bold'))
+                return
+        if opts.ngpon2_twdm_admin_label:
+            interface_instance.data.ngpon2_twdm_admin_label = opts.ngpon2_twdm_admin_label
+        if opts.ngpon2_ptp_admin_label:
+            interface_instance.data.ngpon2_ptp_admin_label = opts.ngpon2_ptp_admin_label
+        if opts.xgs_ponid:
+            interface_instance.data.xgs_ponid = opts.xgs_ponid
+        if opts.xgpon_ponid:
+            interface_instance.data.xgpon_ponid = opts.xgpon_ponid
+        if opts.gpon_ponid:
+            interface_instance.data.gpon_ponid = opts.gpon_ponid
+        if opts.pon_tag:
+            interface_instance.data.pon_tag = opts.pon_tag
+        if opts.ber_calc_period:
+            interface_instance.data.ber_calc_period = opts.ber_calc_period
+        if opts.location:
+            interface_instance.data.location = opts.location
+        if opts.url_to_reach:
+            interface_instance.data.url_to_reach = opts.url_to_reach
+
+        if line.strip() == "create":
+            stub.CreateChanneltermination(interface_instance)
+        elif line.strip() == "update":
+            stub.UpdateChanneltermination(interface_instance)
+        elif line.strip() == "delete":
+            stub.DeleteChanneltermination(interface_instance)
+        return
+
+    def help_vont_ani(self):
+        self.poutput(
+'''
+vont_ani [get | create | update | delete] [-n <name>] [-d <description>] [-a <admin state>]
+         [-l <link up down trap enable type>] [-p <parent reference>]
+         [-s <expected serial number>] [-i <expected registration id>]
+         [-r <preferred channel pair>] [-t <protection channel pair>]
+         [-u <upstream channel speed>] [-o <onu id>]
+
+get:    displays existing vont anis
+        Required flags: None
+create: creates vont ani with the parameters specified with -n, -d, -a, -l, -p, -s, -i, -r, -t, -u and -o.
+        Required flags: <name>
+update: updates existing vont ani specified with parameter -n by changing its parameter values
+        specified with -d, -a, -l, -p, -s, -i, -r, -t, -u and -o.
+        Required flags: <name>
+delete: deletes vont ani specified with parameter -n.
+        Required flags: <name>
+
+-n: <string> name of vont ani.
+-d: <string> description of vont ani.
+-a: <string> admin state of vont ani.
+-l: <enum>   link up down trap enable type.
+-p: <string> parent reference of vont ani must be type of channel partition.
+-s: <string> expected serial number of ONT.
+-i: <string> expected registration id of ONT.
+-r: <string> preferred channel pair must be type of channel pair.
+-t: <string> protection channel pair must be type of channel pair.
+-u: <int>    upstream channel speed of traffic.
+-o <int>     ONU id.
+
+Example:
+
+vont_ani create -n ontani-1-1-1 -a up -p cpart-1-1 -s ALCL00000001 -r cp-1 -u 0 -o 1
+'''
+        )
+
+    @options([
+        make_option('-n', '--name', action="store", dest='name', type='string',
+                    help='name of vont ani', default=None),
+        make_option('-d', '--description', action="store", dest='description',
+                    type='string', help='description of vont ani', default=None),
+        make_option('-a', '--admin_state', action="store", dest='enabled', type='string',
+                    help='admin state of vont ani', default=None),
+        make_option('-l', '--trap', action="store", dest='link_up_down_trap_enable',
+                    type='string', help='link up down trap enable type', default=None),
+        make_option('-p', '--parent_ref', action='store', dest='parent_ref',
+                    type='string', help='parent reference of vont ani must be type of channel partition',
+                    default=None),
+        make_option('-s', '--e_ser_num', action='store', dest='expected_serial_number',
+                    type='string', help='expected serial number of ONT', default=None),
+        make_option('-i', '--e_reg_id', action='store', dest='expected_registration_id',
+                    type='string', help='expected registration id of ONT', default=None),
+        make_option('-r', '--pref_cp', action='store', dest='preferred_chanpair',
+                    type='string', help='preferred channel pair must be type of channel pair',
+                    default=None),
+        make_option('-t', '--prot_cp', action='store', dest='protection_chanpair',
+                    type='string', help='protection channel pair must be type of channel pair',
+                    default=None),
+        make_option('-u', '--up_cs', action='store', dest='upstream_channel_speed',
+                    type='int', help='upstream channel speed of traffic', default=None),
+        make_option('-o', '--onu_id', action='store', dest='onu_id',
+                    type='int', help='onu id', default=None),
+    ])
+
+    def do_vont_ani(self, line, opts):
+        """vont ani get, create -flags <attributes>, update -flags <attributes>, delete -n <name>"""
+        # Ensure that a valid sub-command was provided
+        if line.strip() not in {"get", "create", "update", "delete"}:
+            self.poutput(self.colorize('Error: ', 'red') + \
+                        self.colorize(self.colorize(line.strip(), 'blue'),
+                                      'bold') + ' is not recognized')
+            return
+
+        stub = voltha_pb2.VolthaLocalServiceStub(self.get_channel())
+
+        if line.strip() == "get":
+            if self.device_id:
+                cg, cpart, cp, ct, vont, ont, venet = self.get_interface_based_on_device()
+                print_pb_list_as_table("VOnt Anis for device ID = {}:".format(self.device_id),
+                                       vont, {}, self.poutput)
+            else:
+                interface = stub.GetAllVOntaniConfig(Empty())
+                print_pb_list_as_table("VOnt Anis:",
+                                       interface.v_ontani_config,
+                                       {}, self.poutput)
+            return
+
+        interface_instance = VOntaniConfig(name = opts.name)
+        interface_instance.interface.name = opts.name
+        if opts.description:
+            interface_instance.interface.description = opts.description
+        interface_instance.interface.type = "v-ontani"
+        if opts.enabled:
+            if opts.enabled == "up":
+                interface_instance.interface.enabled = True
+            elif opts.enabled == "down":
+                interface_instance.interface.enabled = False
+            else:
+                self.poutput(self.colorize('Error: ', 'red') + \
+                            self.colorize(self.colorize('Invalid admin state parameter for vont ani', 'blue'),
+                                          'bold'))
+                return
+        if opts.link_up_down_trap_enable:
+            types = ["trap_disabled", "trap_enabled"]
+            try:
+                assert opts.link_up_down_trap_enable in types, \
+                        'Invalid Enum value for VOnt Ani link up down trap enable type \'{}\''\
+                        .format(opts.link_up_down_trap_enable)
+                interface_instance.interface.link_up_down_trap_enable = \
+                    ietf_interfaces_pb2._INTERFACE_LINKUPDOWNTRAPENABLETYPE.values_by_name[opts.link_up_down_trap_enable.upper()].number
+            except AssertionError, e:
+                self.poutput(self.colorize('Error: ', 'red') + \
+                            self.colorize(self.colorize(e.message, 'blue'),
+                                          'bold'))
+                return
+
+        if opts.parent_ref:
+            interface_instance.data.parent_ref = opts.parent_ref
+        if opts.expected_serial_number:
+            interface_instance.data.expected_serial_number = opts.expected_serial_number
+        if opts.expected_registration_id:
+            interface_instance.data.expected_registration_id = opts.expected_registration_id
+        if opts.preferred_chanpair:
+            interface_instance.data.preferred_chanpair = opts.preferred_chanpair
+        if opts.protection_chanpair:
+            interface_instance.data.protection_chanpair = opts.protection_chanpair
+        if opts.upstream_channel_speed:
+            interface_instance.data.upstream_channel_speed = opts.upstream_channel_speed
+        if opts.onu_id:
+            interface_instance.data.onu_id = opts.onu_id
+
+        if line.strip() == "create":
+            stub.CreateVOntani(interface_instance)
+        elif line.strip() == "update":
+            stub.UpdateVOntani(interface_instance)
+        elif line.strip() == "delete":
+            stub.DeleteVOntani(interface_instance)
+        return
+
+    def help_ont_ani(self):
+        self.poutput(
+'''
+ont_ani [get | create | update | delete] [-n <name>] [-d <description>] [-a <admin state>]
+        [-l <link up down trap enable type>] [-u <upstream fec indicator>]
+        [-m <management gem port aes indicator>]
+
+get:    displays existing ont anis
+        Required flags: None
+create: creates ont ani with the parameters specified with -n, -d, -a, -l, -u and -m.
+        Required flags: <name>
+update: updates existing ont ani specified with parameter -n by changing its parameter values
+        specified with -d, -a, -l, -u and -m.
+        Required flags: <name>
+delete: deletes ont ani specified with parameter -n.
+        Required flags: <name>
+
+-n: <string> name of ont ani.
+-d: <string> description of ont ani.
+-a: <string> admin state of ont ani.
+-l: <enum>   link up down trap enable type.
+-u: <bool>   upstream traffic fec indicator.
+-m: <bool>   management gem port aes indicator.
+
+Example:
+
+ont_ani create -n ontani-1-1-1 -a up -u true -m true
+'''
+        )
+
+    @options([
+        make_option('-n', '--name', action="store", dest='name', type='string',
+                    help='name of ont ani', default=None),
+        make_option('-d', '--description', action="store", dest='description',
+                    type='string', help='description of ont ani', default=None),
+        make_option('-a', '--admin_state', action="store", dest='enabled', type='string',
+                    help='admin state of ont ani', default=None),
+        make_option('-l', '--trap', action="store", dest='link_up_down_trap_enable',
+                    type='string', help='link up down trap enable type', default=None),
+        make_option('-u', '--up_fec', action='store', dest='upstream_fec_indicator',
+                    type='string', help='upstream traffic fec indicator', default=None),
+        make_option('-m', '--maes', action='store', dest='mgnt_gemport_aes_indicator',
+                    type='string', help='management gem port aes indicator', default=None),
+    ])
+
+    def do_ont_ani(self, line, opts):
+        """ont ani get, create -flags <attributes>, update -flags <attributes>, delete -n <name>"""
+        # Ensure that a valid sub-command was provided
+        if line.strip() not in {"get", "create", "update", "delete"}:
+            self.poutput(self.colorize('Error: ', 'red') + \
+                        self.colorize(self.colorize(line.strip(), 'blue'),
+                                      'bold') + ' is not recognized')
+            return
+
+        stub = voltha_pb2.VolthaLocalServiceStub(self.get_channel())
+
+        if line.strip() == "get":
+            if self.device_id:
+                cg, cpart, cp, ct, vont, ont, venet = self.get_interface_based_on_device()
+                print_pb_list_as_table("Ont Anis for device ID = {}:".format(self.device_id),
+                                       ont, {}, self.poutput)
+            else:
+                interface = stub.GetAllOntaniConfig(Empty())
+                print_pb_list_as_table("Ont Anis:",
+                                       interface.ontani_config,
+                                       {}, self.poutput)
+            return
+
+        interface_instance = OntaniConfig(name = opts.name)
+        interface_instance.interface.name = opts.name
+        if opts.description:
+            interface_instance.interface.description = opts.description
+        interface_instance.interface.type = "ontani"
+        if opts.enabled:
+            if opts.enabled == "up":
+                interface_instance.interface.enabled = True
+            elif opts.enabled == "down":
+                interface_instance.interface.enabled = False
+            else:
+                self.poutput(self.colorize('Error: ', 'red') + \
+                            self.colorize(self.colorize('Invalid admin state parameter for ont ani', 'blue'),
+                                          'bold'))
+                return
+        if opts.link_up_down_trap_enable:
+            types = ["trap_disabled", "trap_enabled"]
+            try:
+                assert opts.link_up_down_trap_enable in types, \
+                        'Invalid Enum value for Ont Ani link up down trap enable type \'{}\''\
+                        .format(opts.link_up_down_trap_enable)
+                interface_instance.interface.link_up_down_trap_enable = \
+                    ietf_interfaces_pb2._INTERFACE_LINKUPDOWNTRAPENABLETYPE.values_by_name[opts.link_up_down_trap_enable.upper()].number
+            except AssertionError, e:
+                self.poutput(self.colorize('Error: ', 'red') + \
+                            self.colorize(self.colorize(e.message, 'blue'),
+                                          'bold'))
+                return
+
+        if opts.upstream_fec_indicator:
+            if opts.upstream_fec_indicator == 'true':
+                interface_instance.data.upstream_fec_indicator = True
+            elif opts.upstream_fec_indicator == 'false':
+                interface_instance.data.upstream_fec_indicator = False
+            else:
+                m = 'Invalid boolean value for Ont Ani upstream_fec_indicator \'{}\''\
+                    .format(opts.upstream_fec_indicator)
+                self.poutput(self.colorize('Error: ', 'red') + \
+                            self.colorize(self.colorize(m, 'blue'),
+                                          'bold'))
+                return
+        if opts.mgnt_gemport_aes_indicator:
+            if opts.mgnt_gemport_aes_indicator == 'true':
+                interface_instance.data.mgnt_gemport_aes_indicator = True
+            elif opts.mgnt_gemport_aes_indicator == 'false':
+                interface_instance.data.mgnt_gemport_aes_indicator = False
+            else:
+                m = 'Invalid boolean value for Ont Ani mgnt_gemport_aes_indicator \'{}\''\
+                    .format(opts.mgnt_gemport_aes_indicator)
+                self.poutput(self.colorize('Error: ', 'red') + \
+                            self.colorize(self.colorize(m, 'blue'),
+                                          'bold'))
+                return
+
+        if line.strip() == "create":
+            stub.CreateOntani(interface_instance)
+        elif line.strip() == "update":
+            stub.UpdateOntani(interface_instance)
+        elif line.strip() == "delete":
+            stub.DeleteOntani(interface_instance)
+        return
+
+    def help_v_enet(self):
+        self.poutput(
+'''
+v_enet [get | create | update | delete] [-n <name>] [-d <description>] [-a <admin state>]
+       [-l <link up down trap enable type>] [-r <ont ani reference>]
+
+get:    displays existing venets
+        Required flags: None
+create: creates venet with the parameters specified with -n, -d, -a, -l, and -r.
+        Required flags: <name>
+update: updates existing venet specified with parameter -n by changing its parameter values
+        specified with -d, -a, -l, -r.
+        Required flags: <name>
+delete: deletes venet specified with parameter -n.
+        Required flags: <name>
+
+-n: <string> name of venet.
+-d: <string> description of venet.
+-a: <string> admin state of venet.
+-l: <enum>   link up down trap enable type.
+-r: <string> ont ani reference of this venet.
+
+Example:
+
+v_enet create -n venet-1 -a up -r ontani-1-1-1
+'''
+        )
+
+    @options([
+        make_option('-n', '--name', action="store", dest='name', type='string',
+                    help='name of venet', default=None),
+        make_option('-d', '--description', action="store", dest='description',
+                    type='string', help='description of venet', default=None),
+        make_option('-a', '--admin_state', action="store", dest='enabled', type='string',
+                    help='admin state of venet', default=None),
+        make_option('-l', '--trap', action="store", dest='link_up_down_trap_enable',
+                    type='string', help='link up down trap enable type', default=None),
+        make_option('-r', '--ont_ref', action='store', dest='v_ontani_ref',
+                    type='string', help='ont ani reference', default=None),
+    ])
+
+    def do_v_enet(self, line, opts):
+        """v_enet get, create -flags <attributes>, update -flags <attributes>, delete -n <name>"""
+        # Ensure that a valid sub-command was provided
+        if line.strip() not in {"get", "create", "update", "delete"}:
+            self.poutput(self.colorize('Error: ', 'red') + \
+                        self.colorize(self.colorize(line.strip(), 'blue'),
+                                      'bold') + ' is not recognized')
+            return
+
+        stub = voltha_pb2.VolthaLocalServiceStub(self.get_channel())
+
+        if line.strip() == "get":
+            if self.device_id:
+                cg, cpart, cp, ct, vont, ont, venet = self.get_interface_based_on_device()
+                print_pb_list_as_table("VEnet for device ID = {}:".format(self.device_id),
+                                       venet, {}, self.poutput)
+            else:
+                interface = stub.GetAllVEnetConfig(Empty())
+                print_pb_list_as_table("VEnets:",
+                                       interface.v_enet_config,
+                                       {}, self.poutput)
+            return
+
+        interface_instance = VEnetConfig(name = opts.name)
+        interface_instance.interface.name = opts.name
+        if opts.description:
+            interface_instance.interface.description = opts.description
+        interface_instance.interface.type = "v-enet"
+        if opts.enabled:
+            if opts.enabled == "up":
+                interface_instance.interface.enabled = True
+            elif opts.enabled == "down":
+                interface_instance.interface.enabled = False
+            else:
+                self.poutput(self.colorize('Error: ', 'red') + \
+                            self.colorize(self.colorize('Invalid admin state parameter for venet', 'blue'),
+                                          'bold'))
+                return
+        if opts.link_up_down_trap_enable:
+            types = ["trap_disabled", "trap_enabled"]
+            try:
+                assert opts.link_up_down_trap_enable in types, \
+                        'Invalid Enum value for Venet link up down trap enable type \'{}\''\
+                        .format(opts.link_up_down_trap_enable)
+                interface_instance.interface.link_up_down_trap_enable = \
+                    ietf_interfaces_pb2._INTERFACE_LINKUPDOWNTRAPENABLETYPE.values_by_name[opts.link_up_down_trap_enable.upper()].number
+            except AssertionError, e:
+                self.poutput(self.colorize('Error: ', 'red') + \
+                            self.colorize(self.colorize(e.message, 'blue'),
+                                          'bold'))
+                return
+
+        if opts.v_ontani_ref:
+            interface_instance.data.v_ontani_ref = opts.v_ontani_ref
+
+        if line.strip() == "create":
+            stub.CreateVEnet(interface_instance)
+        elif line.strip() == "update":
+            stub.UpdateVEnet(interface_instance)
+        elif line.strip() == "delete":
+            stub.DeleteVEnet(interface_instance)
+        return
diff --git a/netconf/nc_rpc/base/get.py b/netconf/nc_rpc/base/get.py
index 19535f5..b6fdf1e 100644
--- a/netconf/nc_rpc/base/get.py
+++ b/netconf/nc_rpc/base/get.py
@@ -158,6 +158,27 @@
             {'subclass': 'device_groups',
              'rpc': 'VolthaLocalService-ListDeviceGroups'
              },
+            {'subclass': 'channel_groups',
+             'rpc': 'VolthaLocalService-GetAllChannelgroupConfig'
+             },
+            {'subclass': 'channel_partitions',
+             'rpc': 'VolthaLocalService-GetAllChannelpartitionConfig'
+             },
+            {'subclass': 'channel_pairs',
+             'rpc': 'VolthaLocalService-GetAllChannelpairConfig'
+             },
+            {'subclass': 'channel_terminations',
+             'rpc': 'VolthaLocalService-GetAllChannelterminationConfig'
+             },
+            {'subclass': 'ont_anis',
+             'rpc': 'VolthaLocalService-GetAllOntaniConfig'
+             },
+            {'subclass': 'v_ont_anis',
+             'rpc': 'VolthaLocalService-GetAllVOntaniConfig'
+             },
+            {'subclass': 'v_enets',
+             'rpc': 'VolthaLocalService-GetAllVEnetConfig'
+             },
         ],
         'VolthaInstances': [
             {'subclass': None,
diff --git a/ponsim/grpc_server.py b/ponsim/grpc_server.py
index cea0cc4..7ed70d5 100644
--- a/ponsim/grpc_server.py
+++ b/ponsim/grpc_server.py
@@ -23,6 +23,8 @@
     add_PonSimServicer_to_server, PonSimDeviceInfo
 from google.protobuf.empty_pb2 import Empty
 
+from voltha.protos.ponsim_pb2 import XPonSimServicer, add_XPonSimServicer_to_server
+
 _ = third_party
 
 log = structlog.get_logger()
@@ -56,19 +58,39 @@
     def GetStats(self, request, context):
         return self.ponsim.get_stats()
 
+class XPonHandler(XPonSimServicer):
+
+    def __init__(self, thread_pool, x_pon_sim):
+        self.thread_pool = thread_pool
+        self.x_pon_sim = x_pon_sim
+
+    def CreateInterface(self, request, context):
+        self.x_pon_sim.CreateInterface(request)
+        return Empty()
+
+    def UpdateInterface(self, request, context):
+        self.x_pon_sim.UpdateInterface(request)
+        return Empty()
+
+    def RemoveInterface(self, request, context):
+        self.x_pon_sim.RemoveInterface(request)
+        return Empty()
 
 class GrpcServer(object):
 
-    def __init__(self, port, ponsim):
+    def __init__(self, port, ponsim, x_pon_sim):
         self.port = port
         self.thread_pool = futures.ThreadPoolExecutor(max_workers=10)
         self.server = grpc.server(self.thread_pool)
         self.ponsim = ponsim
+        self.x_pon_sim = x_pon_sim
 
     def start(self):
         log.debug('starting')
         handler = FlowUpdateHandler(self.thread_pool, self.ponsim)
         add_PonSimServicer_to_server(handler, self.server)
+        x_pon_handler = XPonHandler(self.thread_pool, self.x_pon_sim)
+        add_XPonSimServicer_to_server(x_pon_handler, self.server)
         self.server.add_insecure_port('[::]:%s' % self.port)
         self.server.start()
         log.info('started')
diff --git a/ponsim/main.py b/ponsim/main.py
index 1b11407..3140afd 100755
--- a/ponsim/main.py
+++ b/ponsim/main.py
@@ -31,6 +31,8 @@
 from ponsim import PonSim
 from realio import RealIo
 
+from ponsim import XPonSim
+
 defs = dict(
     config=os.environ.get('CONFIG', './ponsim.yml'),
     grpc_port=int(os.environ.get('GRPC_PORT', 50060)),
@@ -157,6 +159,7 @@
         # components
         self.io = None
         self.ponsim = None
+        self.x_pon_sim = None
         self.grpc_server = None
 
         self.alarm_config = dict()
@@ -182,7 +185,9 @@
             self.ponsim = PonSim(self.args.onus, self.io.egress, self.alarm_config)
             self.io.register_ponsim(self.ponsim)
 
-            self.grpc_server = GrpcServer(self.args.grpc_port, self.ponsim)
+            self.x_pon_sim = XPonSim()
+
+            self.grpc_server = GrpcServer(self.args.grpc_port, self.ponsim, self.x_pon_sim)
             yield self.grpc_server.start()
 
             self.log.info('started-internal-services')
diff --git a/ponsim/ponsim.py b/ponsim/ponsim.py
index 3adcd4e..619beb1 100644
--- a/ponsim/ponsim.py
+++ b/ponsim/ponsim.py
@@ -471,3 +471,19 @@
         if not isinstance(frame, Packet):
             frame = Ether(frame)
         self.devices[port].ingress(2, frame)
+
+class XPonSim(object):
+    def __init__(self):
+        self.log = structlog.get_logger()
+
+    def CreateInterface(self, request):
+        self.log.info("create-interface-request", interface_type = request.WhichOneof("interface_type"), data = request)
+        return
+
+    def UpdateInterface(self, request):
+        self.log.info("update-interface-request", interface_type = request.WhichOneof("interface_type"), data = request)
+        return
+
+    def RemoveInterface(self, request):
+        self.log.info("remove-interface-request", interface_type = request.WhichOneof("interface_type"), data = request)
+        return
diff --git a/voltha/adapters/adtran_olt/adtran_olt.py b/voltha/adapters/adtran_olt/adtran_olt.py
index 32d34fd..ae66953 100644
--- a/voltha/adapters/adtran_olt/adtran_olt.py
+++ b/voltha/adapters/adtran_olt/adtran_olt.py
@@ -345,3 +345,15 @@
     def unsuppress_alarm(self, filter):
         log.info('unsuppress_alarm', filter=filter)
         raise NotImplementedError()
+
+    def create_interface(self, device, data):
+        raise NotImplementedError()
+
+    def update_interface(self, device, data):
+        raise NotImplementedError()
+
+    def remove_interface(self, device, data):
+        raise NotImplementedError()
+
+    def receive_onu_detect_state(self, device_id, state):
+        raise NotImplementedError()
diff --git a/voltha/adapters/adtran_olt/pon_port.py b/voltha/adapters/adtran_olt/pon_port.py
index 896b8aa..da1bcc4 100644
--- a/voltha/adapters/adtran_olt/pon_port.py
+++ b/voltha/adapters/adtran_olt/pon_port.py
@@ -469,7 +469,8 @@
         adapter.child_device_detected(parent_device_id=olt.device_id,
                                       parent_port_no=self._port_no,
                                       child_device_type=onu.vendor_device,
-                                      proxy_address=proxy)
+                                      proxy_address=proxy,
+                                      admin_state=AdminState.ENABLED)
 
     def get_next_onu_id(self):
         used_ids = [onu.onu_id for onu in self.onus]
diff --git a/voltha/adapters/asfvolt16_olt/asfvolt16_olt.py b/voltha/adapters/asfvolt16_olt/asfvolt16_olt.py
index 94ce1c3..6ef04ce 100644
--- a/voltha/adapters/asfvolt16_olt/asfvolt16_olt.py
+++ b/voltha/adapters/asfvolt16_olt/asfvolt16_olt.py
@@ -31,6 +31,7 @@
                                                device_handler_class = Asfvolt16Handler,
                                                name='asfvolt16_olt',
                                                vendor='Edgecore',
-                                               version='0.1')
+                                               version='0.1',
+                                               device_type='asfvolt16_olt')
         # register for adapter messages
         self.adapter_agent.register_for_inter_adapter_messages()
diff --git a/voltha/adapters/broadcom_onu/broadcom_onu.py b/voltha/adapters/broadcom_onu/broadcom_onu.py
index f852220..732085c 100644
--- a/voltha/adapters/broadcom_onu/broadcom_onu.py
+++ b/voltha/adapters/broadcom_onu/broadcom_onu.py
@@ -164,6 +164,18 @@
     def suppress_alarm(self, filter):
         raise NotImplementedError()
 
+    def create_interface(self, device, data):
+        raise NotImplementedError()
+
+    def update_interface(self, device, data):
+        raise NotImplementedError()
+
+    def remove_interface(self, device, data):
+        raise NotImplementedError()
+
+    def receive_onu_detect_state(self, device_id, state):
+        raise NotImplementedError()
+
     def unsuppress_alarm(self, filter):
         raise NotImplementedError()
 
diff --git a/voltha/adapters/dpoe_onu/dpoe_onu.py b/voltha/adapters/dpoe_onu/dpoe_onu.py
index 9fd1a9f..c261490 100644
--- a/voltha/adapters/dpoe_onu/dpoe_onu.py
+++ b/voltha/adapters/dpoe_onu/dpoe_onu.py
@@ -410,6 +410,18 @@
                   proxy_address=proxy_address, msg=msg)
         self.incoming_messages.put(msg)
 
+    def create_interface(self, device, data):
+        raise NotImplementedError()
+
+    def update_interface(self, device, data):
+        raise NotImplementedError()
+
+    def remove_interface(self, device, data):
+        raise NotImplementedError()
+
+    def receive_onu_detect_state(self, device_id, state):
+        raise NotImplementedError()
+
     def suppress_alarm(self, filter):
         raise NotImplementedError()
 
diff --git a/voltha/adapters/iadapter.py b/voltha/adapters/iadapter.py
index a85913b..5b916ed 100644
--- a/voltha/adapters/iadapter.py
+++ b/voltha/adapters/iadapter.py
@@ -34,14 +34,14 @@
 
 @implementer(IAdapterInterface)
 class IAdapter(object):
-    def __init__(self, adapter_agent, config, device_handler_class, name, vendor, version):
+    def __init__(self, adapter_agent, config, device_handler_class, name, vendor, version, device_type):
         log.debug('Initializing adapter: {} {} {}'.format(vendor, name, version))
         self.adapter_agent = adapter_agent
         self.config = config
         self.name = name
         self.supported_device_types = [
             DeviceType(
-                id=name,
+                id=device_type,
                 adapter=name,
                 accepts_bulk_flow_update=True
             )
@@ -147,17 +147,30 @@
     def unsuppress_alarm(self, filter):
         raise NotImplementedError()
 
+    def create_interface(self, device, data):
+        raise NotImplementedError()
+
+    def update_interface(self, device, data):
+        raise NotImplementedError()
+
+    def remove_interface(self, device, data):
+        raise NotImplementedError()
+
+    def receive_onu_detect_state(self, proxy_address, state):
+        raise NotImplementedError()
+
 """
 OLT Adapter base class
 """
 class OltAdapter(IAdapter):
-    def __init__(self, adapter_agent, config, device_handler_class, name, vendor, version):
+    def __init__(self, adapter_agent, config, device_handler_class, name, vendor, version, device_type):
         super(OltAdapter, self).__init__(adapter_agent,
                                          config,
                                          device_handler_class,
                                          name,
                                          vendor,
-                                         version)
+                                         version,
+                                         device_type)
         self.logical_device_id_to_root_device_id = dict()
 
     def reconcile_device(self, device):
@@ -198,13 +211,15 @@
 ONU Adapter base class
 """
 class OnuAdapter(IAdapter):
-    def __init__(self, adapter_agent, config, device_handler_class, name, vendor, version):
+    def __init__(self, adapter_agent, config, device_handler_class, name, vendor, version, device_type):
         super(OnuAdapter, self).__init__(adapter_agent,
                                          config,
                                          device_handler_class,
                                          name,
                                          vendor,
-                                         version)
+                                         version,
+                                         device_type)
+
     def reconcile_device(self, device):
         self.devices_handlers[device.id] = self.device_handler_class(self, device.id)
         # Reconcile only if state was ENABLED
diff --git a/voltha/adapters/interface.py b/voltha/adapters/interface.py
index 1158a4d..1f2da87 100644
--- a/voltha/adapters/interface.py
+++ b/voltha/adapters/interface.py
@@ -240,6 +240,32 @@
         # TODO work in progress
         # ...
 
+    # PON Mgnt APIs #
+    def create_interface(device, data):
+        """
+        API to create various interfaces (only some PON interfaces as of now)
+        in the devices
+        """
+
+    def update_interface(device, data):
+        """
+        API to update various interfaces (only some PON interfaces as of now)
+        in the devices
+        """
+
+    def remove_interface(device, data):
+        """
+        API to delete various interfaces (only some PON interfaces as of now)
+        in the devices
+        """
+
+    def receive_onu_detect_state(proxy_address, state):
+        """
+        Receive onu detect state in ONU adapter
+        :param proxy_address: ONU device address
+        :param state: ONU detect state (bool)
+        :return: None
+        """
 
 class IAdapterAgent(Interface):
     """
@@ -276,6 +302,7 @@
                               parent_port_no,
                               child_device_type,
                               proxy_address,
+                              admin_state,
                               **kw):
         # TODO add doc
         """"""
@@ -349,3 +376,23 @@
         :param alarm_event_msg: A protobuf message of AlarmEvent type.
         :return: None
         """
+
+    def register_for_onu_detect_state(proxy_address):
+        """
+
+        :return: None
+        """
+
+    def unregister_for_onu_detect_state(proxy_address):
+        """
+
+        :return: None
+        """
+
+    def forward_onu_detect_state(proxy_address, state):
+        """
+        Forward onu detect state to ONU adapter
+        :param proxy_address: ONU device address
+        :param state: ONU detect state (bool)
+        :return: None
+        """
diff --git a/voltha/adapters/maple_olt/maple_olt.py b/voltha/adapters/maple_olt/maple_olt.py
index a690985..528ae01 100644
--- a/voltha/adapters/maple_olt/maple_olt.py
+++ b/voltha/adapters/maple_olt/maple_olt.py
@@ -494,13 +494,24 @@
     def receive_inter_adapter_message(self, msg):
         pass
 
+    def create_interface(self, device, data):
+        raise NotImplementedError()
+
+    def update_interface(self, device, data):
+        raise NotImplementedError()
+
+    def remove_interface(self, device, data):
+        raise NotImplementedError()
+
+    def receive_onu_detect_state(self, device_id, state):
+        raise NotImplementedError()
+
     def suppress_alarm(self, filter):
         raise NotImplementedError()
 
     def unsuppress_alarm(self, filter):
         raise NotImplementedError()
 
-
 class MaplePBClientFactory(pb.PBClientFactory, ReconnectingClientFactory):
     channel = None
     maxDelay = 60
@@ -968,6 +979,7 @@
                     onu_id=onu_id,
                     onu_session_id=tunnel_tag  # tunnel_tag/gem_port, alloc_id
                 ),
+                admin_state=AdminState.ENABLED,
                 vlan=tunnel_tag,
                 serial_number=_data['_vendor_specific']
             )
diff --git a/voltha/adapters/microsemi_olt/DeviceManager.py b/voltha/adapters/microsemi_olt/DeviceManager.py
index 24c3e7a..af3058b 100644
--- a/voltha/adapters/microsemi_olt/DeviceManager.py
+++ b/voltha/adapters/microsemi_olt/DeviceManager.py
@@ -135,6 +135,7 @@
                 onu_id=onu_id,
                 onu_session_id=onu_session_id
             ),
+            admin_state=AdminState.ENABLED,
             vlan=0
         )
 
diff --git a/voltha/adapters/microsemi_olt/microsemi_olt.py b/voltha/adapters/microsemi_olt/microsemi_olt.py
index b50bbeb..64c6d9a 100644
--- a/voltha/adapters/microsemi_olt/microsemi_olt.py
+++ b/voltha/adapters/microsemi_olt/microsemi_olt.py
@@ -142,6 +142,18 @@
         log.debug('bulk-flow-update', device_id=device.id,
                   flows=flows, groups=groups)
 
+    def create_interface(self, device, data):
+        raise NotImplementedError()
+
+    def update_interface(self, device, data):
+        raise NotImplementedError()
+
+    def remove_interface(self, device, data):
+        raise NotImplementedError()
+
+    def receive_onu_detect_state(self, device_id, state):
+        raise NotImplementedError()
+
     def send_proxied_message(self, proxy_address, msg):
         device = self.adaptor_agent.get_device(proxy_address.device_id)
         _, _, comm = self.olts[device.mac_address]
diff --git a/voltha/adapters/pmcs_onu/pmcs_onu.py b/voltha/adapters/pmcs_onu/pmcs_onu.py
index fb27220..2da0e10 100644
--- a/voltha/adapters/pmcs_onu/pmcs_onu.py
+++ b/voltha/adapters/pmcs_onu/pmcs_onu.py
@@ -154,6 +154,18 @@
         log.info('packet-out', logical_device_id=logical_device_id,
                  egress_port_no=egress_port_no, msg_len=len(msg))
 
+    def create_interface(self, device, data):
+        raise NotImplementedError()
+
+    def update_interface(self, device, data):
+        raise NotImplementedError()
+
+    def remove_interface(self, device, data):
+        raise NotImplementedError()
+
+    def receive_onu_detect_state(self, device_id, state):
+        raise NotImplementedError()
+
     def receive_inter_adapter_message(self, msg):
         raise NotImplementedError()
 
diff --git a/voltha/adapters/ponsim_olt/ponsim_olt.py b/voltha/adapters/ponsim_olt/ponsim_olt.py
index 6111eb1..4c40cf7 100644
--- a/voltha/adapters/ponsim_olt/ponsim_olt.py
+++ b/voltha/adapters/ponsim_olt/ponsim_olt.py
@@ -48,6 +48,12 @@
 from voltha.protos.ponsim_pb2 import FlowTable
 from voltha.registry import registry
 
+from voltha.protos.bbf_fiber_base_pb2 import \
+    ChannelgroupConfig, ChannelpartitionConfig, ChannelpairConfig, ChannelterminationConfig, \
+    OntaniConfig, VOntaniConfig, VEnetConfig
+
+from voltha.protos.ponsim_pb2 import InterfaceConfig
+
 _ = third_party
 log = structlog.get_logger()
 
@@ -181,7 +187,8 @@
                                                device_handler_class=PonSimOltHandler,
                                                name='ponsim_olt',
                                                vendor='Voltha project',
-                                               version='0.4')
+                                               version='0.4',
+                                               device_type='ponsim_olt')
 
     def update_pm_config(self, device, pm_config):
         log.info("adapter-update-pm-config", device=device,
@@ -189,6 +196,18 @@
         handler = self.devices_handlers[device.id]
         handler.update_pm_config(device, pm_config)
 
+    def create_interface(self, device, data):
+        log.info('create-interface', device_id=device.id)
+        self.devices_handlers[device.id].create_interface(data)
+
+    def update_interface(self, device, data):
+        log.info('update-interface', device_id=device.id)
+        self.devices_handlers[device.id].update_interface(data)
+
+    def remove_interface(self, device, data):
+        log.info('remove-interface', device_id=device.id)
+        self.devices_handlers[device.id].remove_interface(data)
+
 class PonSimOltHandler(object):
     def __init__(self, adapter, device_id):
         self.adapter = adapter
@@ -322,11 +341,12 @@
             self.adapter_agent.child_device_detected(
                 parent_device_id=device.id,
                 parent_port_no=1,
-                child_device_type='ponsim_onu',
+                child_device_type='PSMO', #''ponsim_onu', # refers notes from ponsim_onu
                 proxy_address=Device.ProxyAddress(
                     device_id=device.id,
                     channel_id=vlan_id
                 ),
+                admin_state=AdminState.ENABLED,
                 vlan=vlan_id
             )
 
@@ -667,3 +687,47 @@
                 log.exception('failed-to-submit-kpis', e=e)
 
         self.pm_metrics.start_collector(_collect)
+
+    def get_interface_config(self, data):
+        interfaceConfig = InterfaceConfig()
+        if isinstance(data, ChannelgroupConfig):
+            interfaceConfig.channel_group_config.CopyFrom(data)
+        elif isinstance(data, ChannelpartitionConfig):
+            interfaceConfig.channel_partition_config.CopyFrom(data)
+        elif isinstance(data, ChannelpairConfig):
+            interfaceConfig.channel_pair_config.CopyFrom(data)
+        elif isinstance(data, ChannelterminationConfig):
+            interfaceConfig.channel_termination_config.CopyFrom(data)
+        elif isinstance(data, OntaniConfig):
+            interfaceConfig.ont_ani_config.CopyFrom(data)
+        elif isinstance(data, VOntaniConfig):
+            interfaceConfig.vont_ani_config.CopyFrom(data)
+        elif isinstance(data, VEnetConfig):
+            interfaceConfig.venet_config.CopyFrom(data)
+        else:
+            return None
+        return interfaceConfig
+
+    def create_interface(self, data):
+        interfaceConfig = self.get_interface_config(data)
+        if interfaceConfig is not None:
+            self.log.info('forwarding-create-interface-request-to-olt-for-interface-type', interface_type=type(data))
+            stub = ponsim_pb2.XPonSimStub(self.get_channel())
+            stub.CreateInterface(interfaceConfig)
+            self.log.info('success')
+
+    def update_interface(self, data):
+        interfaceConfig = self.get_interface_config(data)
+        if interfaceConfig is not None:
+            self.log.info('forwarding-update-interface-request-to-olt-for-interface-type', interface_type=type(data))
+            stub = ponsim_pb2.XPonSimStub(self.get_channel())
+            stub.UpdateInterface(interfaceConfig)
+            self.log.info('success')
+
+    def remove_interface(self, data):
+        interfaceConfig = self.get_interface_config(data)
+        if interfaceConfig is not None:
+            self.log.info('forwarding-remove-interface-request-to-olt-for-interface-type', interface_type=type(data))
+            stub = ponsim_pb2.XPonSimStub(self.get_channel())
+            stub.RemoveInterface(interfaceConfig)
+            self.log.info('success')
diff --git a/voltha/adapters/ponsim_onu/ponsim_onu.py b/voltha/adapters/ponsim_onu/ponsim_onu.py
index f34d6ed..04ae976 100644
--- a/voltha/adapters/ponsim_onu/ponsim_onu.py
+++ b/voltha/adapters/ponsim_onu/ponsim_onu.py
@@ -39,12 +39,15 @@
 
 class PonSimOnuAdapter(OnuAdapter):
     def __init__(self, adapter_agent, config):
+        #DeviceType of ONU should be same as VENDOR ID of ONU Serial Number as specified by standard
+        #requires for identifying correct adapter or ranged ONU
         super(PonSimOnuAdapter, self).__init__(adapter_agent=adapter_agent,
                                                config=config,
                                                device_handler_class = PonSimOnuHandler,
                                                name='ponsim_onu',
                                                vendor='Voltha project',
-                                               version='0.4')
+                                               version='0.4',
+                                               device_type='PSMO')
 
 class PonSimOnuHandler(object):
     def __init__(self, adapter, device_id):
diff --git a/voltha/adapters/simulated_olt/simulated_olt.py b/voltha/adapters/simulated_olt/simulated_olt.py
index e3860b0..ce3242e 100644
--- a/voltha/adapters/simulated_olt/simulated_olt.py
+++ b/voltha/adapters/simulated_olt/simulated_olt.py
@@ -815,6 +815,18 @@
         alarm_lc = LoopingCall(_generate_alarm, device_id)
         alarm_lc.start(30)
 
+    def create_interface(self, device, data):
+        raise NotImplementedError()
+
+    def update_interface(self, device, data):
+        raise NotImplementedError()
+
+    def remove_interface(self, device, data):
+        raise NotImplementedError()
+
+    def receive_onu_detect_state(self, device_id, state):
+        raise NotImplementedError()
+
     # ~~~~~~~~~~~~~~~~~~~~ Embedded test Klein rest server ~~~~~~~~~~~~~~~~~~~~
 
     def get_test_control_site(self):
diff --git a/voltha/adapters/simulated_onu/simulated_onu.py b/voltha/adapters/simulated_onu/simulated_onu.py
index 9fc9288..7a27e45 100644
--- a/voltha/adapters/simulated_onu/simulated_onu.py
+++ b/voltha/adapters/simulated_onu/simulated_onu.py
@@ -387,6 +387,18 @@
         # just place incoming message to a list
         self.incoming_messages.put((proxy_address, msg))
 
+    def create_interface(self, device, data):
+        raise NotImplementedError()
+
+    def update_interface(self, device, data):
+        raise NotImplementedError()
+
+    def remove_interface(self, device, data):
+        raise NotImplementedError()
+
+    def receive_onu_detect_state(self, device_id, state):
+        raise NotImplementedError()
+
     def suppress_alarm(self, filter):
         raise NotImplementedError()
 
diff --git a/voltha/adapters/tibit_olt/tibit_olt.py b/voltha/adapters/tibit_olt/tibit_olt.py
index 4bf40c9..91ff213 100644
--- a/voltha/adapters/tibit_olt/tibit_olt.py
+++ b/voltha/adapters/tibit_olt/tibit_olt.py
@@ -454,6 +454,7 @@
                                     device_id=device.id,
                                     channel_id=vlan_id
                                     ),
+                                    admin_state=AdminState.ENABLED,
                                     vlan=vlan_id
                             )
 
@@ -1382,3 +1383,15 @@
         # Get and process the Set Response
         rc = []
         yield self._handle_set_resp(olt_mac, action, rc)
+
+    def create_interface(self, device, data):
+        raise NotImplementedError()
+
+    def update_interface(self, device, data):
+        raise NotImplementedError()
+
+    def remove_interface(self, device, data):
+        raise NotImplementedError()
+
+    def receive_onu_detect_state(self, device_id, state):
+        raise NotImplementedError()
diff --git a/voltha/adapters/tibit_onu/tibit_onu.py b/voltha/adapters/tibit_onu/tibit_onu.py
index 7ee421f..bc18dc7 100644
--- a/voltha/adapters/tibit_onu/tibit_onu.py
+++ b/voltha/adapters/tibit_onu/tibit_onu.py
@@ -537,6 +537,18 @@
                   proxy_address=proxy_address, msg=msg.show(dump=True))
         self.incoming_messages.put(msg)
 
+    def create_interface(self, device, data):
+        raise NotImplementedError()
+
+    def update_interface(self, device, data):
+        raise NotImplementedError()
+
+    def remove_interface(self, device, data):
+        raise NotImplementedError()
+
+    def receive_onu_detect_state(self, device_id, state):
+        raise NotImplementedError()
+
     @inlineCallbacks
     def _message_exchange(self, device):
 
diff --git a/voltha/core/adapter_agent.py b/voltha/core/adapter_agent.py
index 9140cc5..d966c3b 100644
--- a/voltha/core/adapter_agent.py
+++ b/voltha/core/adapter_agent.py
@@ -41,7 +41,6 @@
 from voltha.registry import registry
 from common.utils.id_generation import create_cluster_device_id
 
-
 @implementer(IAdapterAgent)
 class AdapterAgent(object):
     """
@@ -66,6 +65,7 @@
         self.event_bus = EventBusClient()
         self.packet_out_subscription = None
         self.log = structlog.get_logger(adapter_name=adapter_name)
+        self._onu_detect_event_subscriptions = {}
 
     @inlineCallbacks
     def start(self):
@@ -194,6 +194,15 @@
     # def update_pm_collection(self, device, pm_collection_config):
     #    return self.adapter.update_pm_collection(device, pm_collection_config)
 
+    def create_interface (self, device, data):
+        return self.adapter.create_interface (device, data)
+
+    def update_interface (self, device, data):
+        return self.adapter.update_interface (device, data)
+
+    def remove_interface(self, device, data):
+        return self.adapter.remove_interface(device, data)
+
 
     # ~~~~~~~~~~~~~~~~~~~ Adapter-Facing Service ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -211,10 +220,11 @@
         :return: Child Device Object or None
         """
         # Get all arguments to be used for comparison
-        # Note that for now we are only matching on the ONU ID
+        # Note that for now we are only matching on the ONU ID & SERIAL NUMBER
         # Other matching fields can be added as required in the future
         onu_id = kwargs.pop('onu_id', None)
-        if onu_id is None: return None
+        serial_number = kwargs.pop('serial_number', None)
+        if onu_id is None and serial_number is None: return None
 
         # Get all devices
         devices = self.root_proxy.get('/devices')
@@ -228,8 +238,22 @@
             device = self.get_device(child_id)
 
             # Does this child device match the passed in ONU ID?
-            if device.proxy_address.onu_id != onu_id:
-                found = False
+            found_onu_id = False
+            if onu_id is not None:
+                if device.proxy_address.onu_id == onu_id:
+                    found_onu_id = True
+
+            # Does this child device match the passed in SERIAL NUMBER?
+            found_serial_number = False
+            if serial_number is not None:
+                if device.serial_number == serial_number:
+                    found_serial_number = True
+            # Match ONU ID and SERIAL NUMBER
+            if onu_id is not None and serial_number is not None:
+                found = found_onu_id & found_serial_number
+            # Otherwise ONU ID or SERIAL NUMBER
+            else:
+                found = found_onu_id | found_serial_number
 
             # Return the matched child device
             if found is True:
@@ -509,17 +533,17 @@
                               parent_port_no,
                               child_device_type,
                               proxy_address,
+                              admin_state,
                               **kw):
         # we create new ONU device objects and insert them into the config
-        # TODO should we auto-enable the freshly created device? Probably.
         device = Device(
             id=create_cluster_device_id(self.core.core_store_id),
             # id=uuid4().hex[:12],
             type=child_device_type,
             parent_id=parent_device_id,
             parent_port_no=parent_port_no,
-            admin_state=AdminState.ENABLED,
             proxy_address=proxy_address,
+            admin_state=admin_state,
             **kw
         )
         self._make_up_to_date(
@@ -581,6 +605,13 @@
             self._make_up_to_date(
                 '/devices', device.id, device)
 
+    def delete_child_device(self, parent_device_id, child_device_id):
+        onu_device = self.root_proxy.get('/devices/{}'.format(child_device_id))
+        if onu_device is not None:
+            if onu_device.parent_id == parent_device_id:
+                self.log.debug('deleting-child-device', parent_device_id=parent_device_id, child_device_id=child_device_id)
+                self._remove_node('/devices', child_device_id)
+
     def _gen_rx_proxy_address_topic(self, proxy_address):
         """Generate unique topic name specific to this proxy address for rx"""
         topic = 'rx:' + MessageToJson(proxy_address)
@@ -723,3 +754,28 @@
         except Exception as e:
             self.log.exception('failed-alarm-submission',
                                type=type(alarm_event_msg))
+
+    # ~~~~~~~~~~~~~~~~~~~ Handle ONU detect ~~~~~~~~~~~~~~~~~~~~~
+
+    def _gen_onu_detect_proxy_address_topic(self, device_id):
+        """Generate unique topic name specific to this device id for onu detect"""
+        topic = str('onu_detect:{}'.format(device_id))
+        return topic
+
+    def register_for_onu_detect_state(self, device_id):
+        topic = self._gen_onu_detect_proxy_address_topic(device_id)
+        self._onu_detect_event_subscriptions[topic] = self.event_bus.subscribe(
+            topic,
+            lambda t, m: self._forward_onu_detect_state(device_id, m))
+
+    def unregister_for_onu_detect_state(self, device_id):
+        topic = self._gen_onu_detect_proxy_address_topic(device_id)
+        self.event_bus.unsubscribe(self._onu_detect_event_subscriptions[topic])
+        del self._onu_detect_event_subscriptions[topic]
+
+    def _forward_onu_detect_state(self, device_id, state):
+        self.adapter.receive_onu_detect_state(device_id, state)
+
+    def forward_onu_detect_state(self, device_id, state):
+        topic = self._gen_onu_detect_proxy_address_topic(device_id)
+        self.event_bus.publish(topic, state)
diff --git a/voltha/core/config/config_rev_persisted.py b/voltha/core/config/config_rev_persisted.py
index 3464664..ad8711f 100644
--- a/voltha/core/config/config_rev_persisted.py
+++ b/voltha/core/config/config_rev_persisted.py
@@ -133,5 +133,5 @@
 def tmp_cls_loader(module_name, cls_name):
     # TODO this shall be generalized
     from voltha.protos import voltha_pb2, health_pb2, adapter_pb2, \
-        logical_device_pb2, device_pb2, openflow_13_pb2
+        logical_device_pb2, device_pb2, openflow_13_pb2, bbf_fiber_base_pb2
     return getattr(locals()[module_name], cls_name)
diff --git a/voltha/core/core.py b/voltha/core/core.py
index 80bc5c1..7ddb5b8 100644
--- a/voltha/core/core.py
+++ b/voltha/core/core.py
@@ -34,6 +34,10 @@
 from voltha.protos.voltha_pb2 import \
     Device, LogicalDevice, AlarmFilter
 from voltha.registry import IComponent
+from xpon_agent import XponAgent
+from xpon_handler import XponHandler
+from voltha.protos.bbf_fiber_base_pb2 import ChannelgroupConfig, ChannelpartitionConfig, \
+    ChannelpairConfig, OntaniConfig, VOntaniConfig, VEnetConfig
 
 log = structlog.get_logger()
 
@@ -58,6 +62,7 @@
             instance_id=instance_id,
             version=version,
             log_level=log_level)
+        self.xpon_handler = XponHandler(self)
         self.local_handler = LocalHandler(
             core=self,
             instance_id=instance_id,
@@ -70,6 +75,7 @@
         self.alarm_filter_agent = None
         self.packet_in_queue = Queue()
         self.change_event_queue = Queue()
+        self.xpon_agent = XponAgent(self)
 
     @inlineCallbacks
     def start(self, config_backend=None):
@@ -151,6 +157,10 @@
             self._handle_add_device(data)
         elif isinstance(data, LogicalDevice):
             self._handle_add_logical_device(data)
+        elif isinstance(data, (ChannelgroupConfig, ChannelpartitionConfig,
+                               ChannelpairConfig, OntaniConfig, VOntaniConfig,
+                               VEnetConfig)):
+            self.xpon_agent.create_interface(data)
         elif isinstance(data, AlarmFilter):
             self._handle_add_alarm_filter(data)
         else:
@@ -162,6 +172,10 @@
             self._handle_remove_device(data)
         elif isinstance(data, LogicalDevice):
             self._handle_remove_logical_device(data)
+        elif isinstance(data, (ChannelgroupConfig, ChannelpartitionConfig,
+                                ChannelpairConfig, OntaniConfig, VOntaniConfig,
+                                VEnetConfig)):
+            self.xpon_agent.remove_interface(data)
         elif isinstance(data, AlarmFilter):
             self._handle_remove_alarm_filter(data)
         else:
@@ -177,6 +191,7 @@
         path = '/devices/{}'.format(device.id)
         assert device.id not in self.device_agents
         self.device_agents[device.id] = yield DeviceAgent(self, device).start()
+        self.xpon_agent.register_interface(device.id, path, update=False)
 
     @inlineCallbacks
     def _handle_reconcile_existing_device(self, device, reconcile):
@@ -190,6 +205,8 @@
     @inlineCallbacks
     def _handle_remove_device(self, device):
         if device.id in self.device_agents:
+            path = '/devices/{}'.format(device.id)
+            self.xpon_agent.unregister_interface(device.id, path, update=False)
             if self.alarm_filter_agent is not None:
                 self.alarm_filter_agent.remove_device_filters(device)
 
diff --git a/voltha/core/device_agent.py b/voltha/core/device_agent.py
index 479ec6f..0de15bc 100644
--- a/voltha/core/device_agent.py
+++ b/voltha/core/device_agent.py
@@ -23,7 +23,7 @@
 from twisted.internet.defer import inlineCallbacks, returnValue
 
 from voltha.core.config.config_proxy import CallbackType
-from voltha.protos.common_pb2 import AdminState, OperStatus
+from voltha.protos.common_pb2 import AdminState, OperStatus, ConnectStatus
 from voltha.registry import registry
 from voltha.protos.openflow_13_pb2 import Flows, FlowGroups
 
@@ -208,6 +208,9 @@
     def update_device(self, device):
         self.last_data = device  # so that we don't propagate back
         self.proxy.update('/', device)
+        if device.oper_status == OperStatus.ACTIVE and device.connect_status == ConnectStatus.REACHABLE:
+            self.log.info('replay-create-interfaces ', device=device.id)
+            self.core.xpon_agent.replay_interface(device.id)
 
     def update_device_pm_config(self, device_pm_config, init=False):
         self.callback_data = init# so that we don't push init data
@@ -333,4 +336,3 @@
 
         else:
             raise NotImplementedError()
-
diff --git a/voltha/core/global_handler.py b/voltha/core/global_handler.py
index 7c80826..ab02cf0 100644
--- a/voltha/core/global_handler.py
+++ b/voltha/core/global_handler.py
@@ -502,6 +502,316 @@
             log.info('grpc-success-response', response=response)
             returnValue(response)
 
+    # bbf_fiber rpcs start
+    @twisted_async
+    def GetAllChannelgroupConfig(self, request, context):
+        log.warning('temp-limited-implementation')
+        # TODO dispatching to local instead of collecting all
+        return self.dispatcher.dispatch(
+            self.instance_id,
+            VolthaLocalServiceStub,
+            'GetAllChannelgroupConfig',
+            request,
+            context)
+
+    @twisted_async
+    def CreateChannelgroup(self, request, context):
+        log.warning('temp-limited-implementation')
+        # TODO dispatching to local instead of collecting all
+        return self.dispatcher.dispatch(
+            self.instance_id,
+            VolthaLocalServiceStub,
+            'CreateChannelgroup',
+            request,
+            context)
+
+    @twisted_async
+    def UpdateChannelgroup(self, request, context):
+        log.warning('temp-limited-implementation')
+        # TODO dispatching to local instead of collecting all
+        return self.dispatcher.dispatch(
+            self.instance_id,
+            VolthaLocalServiceStub,
+            'UpdateChannelgroup',
+            request,
+            context)
+
+    @twisted_async
+    def DeleteChannelgroup(self, request, context):
+        log.warning('temp-limited-implementation')
+        # TODO dispatching to local instead of collecting all
+        return self.dispatcher.dispatch(
+            self.instance_id,
+            VolthaLocalServiceStub,
+            'DeleteChannelgroup',
+            request,
+            context)
+
+    @twisted_async
+    def GetAllChannelpartitionConfig(self, request, context):
+        log.warning('temp-limited-implementation')
+        # TODO dispatching to local instead of collecting all
+        return self.dispatcher.dispatch(
+            self.instance_id,
+            VolthaLocalServiceStub,
+            'GetAllChannelpartitionConfig',
+            request,
+            context)
+
+    @twisted_async
+    def CreateChannelpartition(self, request, context):
+        log.warning('temp-limited-implementation')
+        # TODO dispatching to local instead of collecting all
+        return self.dispatcher.dispatch(
+            self.instance_id,
+            VolthaLocalServiceStub,
+            'CreateChannelpartition',
+            request,
+            context)
+
+    @twisted_async
+    def UpdateChannelpartition(self, request, context):
+        log.warning('temp-limited-implementation')
+        # TODO dispatching to local instead of collecting all
+        return self.dispatcher.dispatch(
+            self.instance_id,
+            VolthaLocalServiceStub,
+            'UpdateChannelpartition',
+            request,
+            context)
+
+    @twisted_async
+    def DeleteChannelpartition(self, request, context):
+        log.warning('temp-limited-implementation')
+        # TODO dispatching to local instead of collecting all
+        return self.dispatcher.dispatch(
+            self.instance_id,
+            VolthaLocalServiceStub,
+            'DeleteChannelpartition',
+            request,
+            context)
+
+    @twisted_async
+    def GetAllChannelpairConfig(self, request, context):
+        log.warning('temp-limited-implementation')
+        # TODO dispatching to local instead of collecting all
+        return self.dispatcher.dispatch(
+            self.instance_id,
+            VolthaLocalServiceStub,
+            'GetAllChannelpairConfig',
+            request,
+            context)
+
+    @twisted_async
+    def CreateChannelpair(self, request, context):
+        log.warning('temp-limited-implementation')
+        # TODO dispatching to local instead of collecting all
+        return self.dispatcher.dispatch(
+            self.instance_id,
+            VolthaLocalServiceStub,
+            'CreateChannelpair',
+            request,
+            context)
+
+    @twisted_async
+    def UpdateChannelpair(self, request, context):
+        log.warning('temp-limited-implementation')
+        # TODO dispatching to local instead of collecting all
+        return self.dispatcher.dispatch(
+            self.instance_id,
+            VolthaLocalServiceStub,
+            'UpdateChannelpair',
+            request,
+            context)
+
+    @twisted_async
+    def DeleteChannelpair(self, request, context):
+        log.warning('temp-limited-implementation')
+        # TODO dispatching to local instead of collecting all
+        return self.dispatcher.dispatch(
+            self.instance_id,
+            VolthaLocalServiceStub,
+            'DeleteChannelpair',
+            request,
+            context)
+
+    @twisted_async
+    def GetAllChannelterminationConfig(self, request, context):
+        log.warning('temp-limited-implementation')
+        # TODO dispatching to local instead of collecting all
+        return self.dispatcher.dispatch(
+            self.instance_id,
+            VolthaLocalServiceStub,
+            'GetAllChannelterminationConfig',
+            request,
+            context)
+
+    @twisted_async
+    def CreateChanneltermination(self, request, context):
+        log.warning('temp-limited-implementation')
+        # TODO dispatching to local instead of collecting all
+        return self.dispatcher.dispatch(
+            self.instance_id,
+            VolthaLocalServiceStub,
+            'CreateChanneltermination',
+            request,
+            context)
+
+    @twisted_async
+    def UpdateChanneltermination(self, request, context):
+        log.warning('temp-limited-implementation')
+        # TODO dispatching to local instead of collecting all
+        return self.dispatcher.dispatch(
+            self.instance_id,
+            VolthaLocalServiceStub,
+            'UpdateChanneltermination',
+            request,
+            context)
+
+    @twisted_async
+    def DeleteChanneltermination(self, request, context):
+        log.warning('temp-limited-implementation')
+        # TODO dispatching to local instead of collecting all
+        return self.dispatcher.dispatch(
+            self.instance_id,
+            VolthaLocalServiceStub,
+            'DeleteChanneltermination',
+            request,
+            context)
+
+    @twisted_async
+    def GetAllOntaniConfig(self, request, context):
+        log.warning('temp-limited-implementation')
+        # TODO dispatching to local instead of collecting all
+        return self.dispatcher.dispatch(
+            self.instance_id,
+            VolthaLocalServiceStub,
+            'GetAllOntaniConfig',
+            request,
+            context)
+
+    @twisted_async
+    def CreateOntani(self, request, context):
+        log.warning('temp-limited-implementation')
+        # TODO dispatching to local instead of collecting all
+        return self.dispatcher.dispatch(
+            self.instance_id,
+            VolthaLocalServiceStub,
+            'CreateOntani',
+            request,
+            context)
+
+    @twisted_async
+    def UpdateOntani(self, request, context):
+        log.warning('temp-limited-implementation')
+        # TODO dispatching to local instead of collecting all
+        return self.dispatcher.dispatch(
+            self.instance_id,
+            VolthaLocalServiceStub,
+            'UpdateOntani',
+            request,
+            context)
+
+    @twisted_async
+    def DeleteOntani(self, request, context):
+        log.warning('temp-limited-implementation')
+        # TODO dispatching to local instead of collecting all
+        return self.dispatcher.dispatch(
+            self.instance_id,
+            VolthaLocalServiceStub,
+            'DeleteOntani',
+            request,
+            context)
+
+    @twisted_async
+    def GetAllVOntaniConfig(self, request, context):
+        log.warning('temp-limited-implementation')
+        # TODO dispatching to local instead of collecting all
+        return self.dispatcher.dispatch(
+            self.instance_id,
+            VolthaLocalServiceStub,
+            'GetAllVOntaniConfig',
+            request,
+            context)
+
+    @twisted_async
+    def CreateVOntani(self, request, context):
+        log.warning('temp-limited-implementation')
+        # TODO dispatching to local instead of collecting all
+        return self.dispatcher.dispatch(
+            self.instance_id,
+            VolthaLocalServiceStub,
+            'CreateVOntani',
+            request,
+            context)
+
+    @twisted_async
+    def UpdateVOntani(self, request, context):
+        log.warning('temp-limited-implementation')
+        # TODO dispatching to local instead of collecting all
+        return self.dispatcher.dispatch(
+            self.instance_id,
+            VolthaLocalServiceStub,
+            'UpdateVOntani',
+            request,
+            context)
+
+    @twisted_async
+    def DeleteVOntani(self, request, context):
+        log.warning('temp-limited-implementation')
+        # TODO dispatching to local instead of collecting all
+        return self.dispatcher.dispatch(
+            self.instance_id,
+            VolthaLocalServiceStub,
+            'DeleteVOntani',
+            request,
+            context)
+
+    @twisted_async
+    def GetAllVEnetConfig(self, request, context):
+        log.warning('temp-limited-implementation')
+        # TODO dispatching to local instead of collecting all
+        return self.dispatcher.dispatch(
+            self.instance_id,
+            VolthaLocalServiceStub,
+            'GetAllVEnetConfig',
+            request,
+            context)
+
+    @twisted_async
+    def CreateVEnet(self, request, context):
+        log.warning('temp-limited-implementation')
+        # TODO dispatching to local instead of collecting all
+        return self.dispatcher.dispatch(
+            self.instance_id,
+            VolthaLocalServiceStub,
+            'CreateVEnet',
+            request,
+            context)
+
+    @twisted_async
+    def UpdateVEnet(self, request, context):
+        log.warning('temp-limited-implementation')
+        # TODO dispatching to local instead of collecting all
+        return self.dispatcher.dispatch(
+            self.instance_id,
+            VolthaLocalServiceStub,
+            'UpdateVEnet',
+            request,
+            context)
+
+    @twisted_async
+    def DeleteVEnet(self, request, context):
+        log.warning('temp-limited-implementation')
+        # TODO dispatching to local instead of collecting all
+        return self.dispatcher.dispatch(
+            self.instance_id,
+            VolthaLocalServiceStub,
+            'DeleteVEnet',
+            request,
+            context)
+    # bbf_fiber rpcs end
+
     @twisted_async
     @inlineCallbacks
     def CreateAlarmFilter(self, request, context):
diff --git a/voltha/core/local_handler.py b/voltha/core/local_handler.py
index bc36a35..fb02ecc 100644
--- a/voltha/core/local_handler.py
+++ b/voltha/core/local_handler.py
@@ -32,6 +32,7 @@
     AlarmFilter, AlarmFilters, SelfTestResponse
 from voltha.protos.device_pb2 import PmConfigs, Images
 from voltha.registry import registry
+from requests.api import request
 
 log = structlog.get_logger()
 
@@ -66,6 +67,8 @@
         else:
             self.root = ConfigRoot(VolthaInstance(**self.init_kw))
 
+        self.core.xpon_handler.start(self.root)
+
         registry('grpc_server').register(
             add_VolthaLocalServiceServicer_to_server, self)
         log.info('started')
@@ -564,6 +567,120 @@
             context.set_code(StatusCode.NOT_FOUND)
             return DeviceGroup()
 
+    # bbf_fiber rpcs start
+    @twisted_async
+    def GetAllChannelgroupConfig(self, request, context):
+        return self.core.xpon_handler.get_all_channel_group_config(request, context)
+
+    @twisted_async
+    def CreateChannelgroup(self, request, context):
+        return self.core.xpon_handler.create_channel_group(request, context)
+
+    @twisted_async
+    def UpdateChannelgroup(self, request, context):
+        return self.core.xpon_handler.update_channel_group(request, context)
+
+    @twisted_async
+    def DeleteChannelgroup(self, request, context):
+        return self.core.xpon_handler.delete_channel_group(request, context)
+
+    @twisted_async
+    def GetAllChannelpartitionConfig(self, request, context):
+        return self.core.xpon_handler.get_all_channel_partition_config(request, context)
+
+    @twisted_async
+    def CreateChannelpartition(self, request, context):
+        return self.core.xpon_handler.create_channel_partition(request, context)
+
+    @twisted_async
+    def UpdateChannelpartition(self, request, context):
+        return self.core.xpon_handler.update_channel_partition(request, context)
+
+    @twisted_async
+    def DeleteChannelpartition(self, request, context):
+        return self.core.xpon_handler.delete_channel_partition(request, context)
+
+    @twisted_async
+    def GetAllChannelpairConfig(self, request, context):
+        return self.core.xpon_handler.get_all_channel_pair_config(request, context)
+
+    @twisted_async
+    def CreateChannelpair(self, request, context):
+        return self.core.xpon_handler.create_channel_pair(request, context)
+
+    @twisted_async
+    def UpdateChannelpair(self, request, context):
+        return self.core.xpon_handler.update_channel_pair(request, context)
+
+    @twisted_async
+    def DeleteChannelpair(self, request, context):
+        return self.core.xpon_handler.delete_channel_pair(request, context)
+
+    @twisted_async
+    def GetAllChannelterminationConfig(self, request, context):
+        return self.core.xpon_handler.get_all_channel_termination_config(request, context)
+
+    @twisted_async
+    def CreateChanneltermination(self, request, context):
+        return self.core.xpon_handler.create_channel_termination(request, context)
+
+    @twisted_async
+    def UpdateChanneltermination(self, request, context):
+        return self.core.xpon_handler.update_channel_termination(request, context)
+
+    @twisted_async
+    def DeleteChanneltermination(self, request, context):
+        return self.core.xpon_handler.delete_channel_termination(request, context)
+
+    @twisted_async
+    def GetAllOntaniConfig(self, request, context):
+        return self.core.xpon_handler.get_all_ont_ani_config(request, context)
+
+    @twisted_async
+    def CreateOntani(self, request, context):
+        return self.core.xpon_handler.create_ont_ani(request, context)
+
+    @twisted_async
+    def UpdateOntani(self, request, context):
+        return self.core.xpon_handler.update_ont_ani(request, context)
+
+    @twisted_async
+    def DeleteOntani(self, request, context):
+        return self.core.xpon_handler.delete_ont_ani(request, context)
+
+    @twisted_async
+    def GetAllVOntaniConfig(self, request, context):
+        return self.core.xpon_handler.get_all_v_ont_ani_config(request, context)
+
+    @twisted_async
+    def CreateVOntani(self, request, context):
+        return self.core.xpon_handler.create_v_ont_ani(request, context)
+
+    @twisted_async
+    def UpdateVOntani(self, request, context):
+        return self.core.xpon_handler.update_v_ont_ani(request, context)
+
+    @twisted_async
+    def DeleteVOntani(self, request, context):
+        return self.core.xpon_handler.delete_v_ont_ani(request, context)
+
+    @twisted_async
+    def GetAllVEnetConfig(self, request, context):
+        return self.core.xpon_handler.get_all_v_enet_config(request, context)
+
+    @twisted_async
+    def CreateVEnet(self, request, context):
+        return self.core.xpon_handler.create_v_enet(request, context)
+
+    @twisted_async
+    def UpdateVEnet(self, request, context):
+        return self.core.xpon_handler.update_v_enet(request, context)
+
+    @twisted_async
+    def DeleteVEnet(self, request, context):
+        return self.core.xpon_handler.delete_v_enet(request, context)
+    # bbf_fiber rpcs end
+
     def StreamPacketsOut(self, request_iterator, context):
 
         @twisted_async
diff --git a/voltha/core/xpon_agent.py b/voltha/core/xpon_agent.py
new file mode 100644
index 0000000..489ff90
--- /dev/null
+++ b/voltha/core/xpon_agent.py
@@ -0,0 +1,371 @@
+# Copyright 2017 the original author or authors.
+#
+# 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 structlog
+import sys
+import functools
+
+from voltha.registry import registry
+from voltha.core.config.config_proxy import CallbackType
+from voltha.protos.bbf_fiber_base_pb2 import ChannelgroupConfig, ChannelpartitionConfig, \
+    ChannelpairConfig, ChannelterminationConfig, OntaniConfig, VOntaniConfig, VEnetConfig
+from voltha.protos.device_pb2 import Device
+from voltha.protos.common_pb2 import AdminState
+
+log = structlog.get_logger()
+
+class XponAgent(object):
+
+    interfaces = {ChannelgroupConfig: {'path': '/channel_groups/{}', 'path_keys': ['name'], 'device_id' : ''},
+                  ChannelpartitionConfig: {'path': '/channel_partitions/{}', 'path_keys': ['name'], 'device_id' : ''},
+                  ChannelpairConfig: {'path': '/channel_pairs/{}', 'path_keys': ['name'], 'device_id' : ''},
+                  ChannelterminationConfig: {'path': '/devices/{}/channel_terminations/{}', 'path_keys': ['id', 'name'], 'device_id' : 'id'},
+                  OntaniConfig: {'path': '/ont_anis/{}', 'path_keys': ['name'], 'device_id' : ''},
+                  VOntaniConfig: {'path': '/v_ont_anis/{}', 'path_keys': ['name'], 'device_id' : ''},
+                  VEnetConfig: {'path': '/v_enets/{}', 'path_keys': ['name'], 'device_id' : ''}
+                  }
+
+    interface_stack = {ChannelgroupConfig: {'parent': None, 'parent_path' : None, 'parent_path_keys': [None]},
+                       ChannelpartitionConfig: {'parent': ChannelgroupConfig, 'parent_path' : '/channel_groups/{}', 'parent_path_keys': ['data.channelgroup_ref']},
+                       ChannelpairConfig: {'parent': ChannelpartitionConfig, 'parent_path': '/channel_partitions/{}', 'parent_path_keys': ['data.channelpartition_ref']},
+                       ChannelterminationConfig: {'parent': ChannelpairConfig, 'parent_path': '/channel_pairs/{}', 'parent_path_keys': ['data.channelpair_ref']},
+                       #VOntaniConfig: {'parent': ChannelpartitionConfig, 'parent_path': '/channel_partitions/{}', 'parent_path_keys': ['data.channelpartition_ref']},
+                       VOntaniConfig: {'parent': ChannelpairConfig, 'parent_path': '/channel_pairs/{}', 'parent_path_keys': ['data.preferred_chanpair']},
+                       OntaniConfig: {'parent': VOntaniConfig, 'parent_path': '/v_ont_anis/{}', 'parent_path_keys': ['name']},
+                       VEnetConfig: {'parent': VOntaniConfig, 'parent_path': '/v_ont_anis/{}', 'parent_path_keys': ['data.v_ontani_ref']}
+                      }
+
+    def __init__(self, core):
+        self.core = core
+        self.preData = None
+        self.inReplay = False
+        return
+
+    def get_device_adapter_agent(self, device_id):
+        device = self.core.get_proxy('/devices/{}'.format(device_id)).get()
+        assert device.adapter != ''
+        adapter_agent = registry('adapter_loader').get_agent(device.adapter)
+        log.debug('get-device-adapter-agent', device=device, adapter_agent=adapter_agent)
+        return device, adapter_agent
+
+    def get_interface_path(self, data):
+        val = self.interfaces[type(data)]
+        id_val = {}
+        count = 0
+        for key in val['path_keys']:
+            id_val[count] = getattr(data, key)
+            count+=1
+        path = val['path'].format(*id_val.values())
+        return path
+
+    def get_device_id(self, data):
+        val = self.interfaces[type(data)]
+        device_id = None if val['device_id'] is '' else getattr(data, val['device_id'])
+        if device_id is None:
+            if(isinstance(data, ChannelpairConfig)):
+                device_items = self.core.get_proxy('/').get('/devices')
+                for device_item in device_items:
+                    items = self.core.get_proxy('/').get(
+                        '/devices/{}/channel_terminations'.format(device_item.id))
+                    for item in items:
+                        if item.data.channelpair_ref == data.name:
+                            return self.get_device_id(item)
+                return None
+            elif(isinstance(data, ChannelpartitionConfig)):
+                items = self.core.get_proxy('/').get('/channel_pairs')
+                for item in items:
+                    if item.data.channelpartition_ref == data.name:
+                        return self.get_device_id(item)
+                return None
+            elif(isinstance(data, ChannelgroupConfig)):
+                items = self.core.get_proxy('/').get('/channel_partitions')
+                for item in items:
+                    if item.data.channelgroup_ref == data.name:
+                        return self.get_device_id(item)
+                return None
+            # Take care of ont ani and v ont ani
+            elif(isinstance(data, VOntaniConfig)):
+                channel_part_items = self.core.get_proxy('/').get('/channel_partitions')
+                channel_pair_items = self.core.get_proxy('/').get('/channel_pairs')
+                for channel_part_item in channel_part_items:
+                    if channel_part_item.name == data.data.parent_ref:
+                        return self.get_device_id(channel_part_item)
+                for channel_pair_item in channel_pair_items:
+                    if channel_pair_item.name == data.data.preferred_chanpair or \
+                        channel_pair_item.name == data.data.protection_chanpair:
+                            return self.get_device_id(channel_pair_item)
+                return None
+            elif(isinstance(data, OntaniConfig)):
+                v_ont_ani_items = self.core.get_proxy('/').get('/v_ont_anis')
+                for v_ont_ani_item in v_ont_ani_items:
+                    if v_ont_ani_item.name == data.name:
+                        return self.get_device_id(v_ont_ani_item)
+                return None
+            elif(isinstance(data, VEnetConfig)):
+                v_ont_ani_items = self.core.get_proxy('/').get('/v_ont_anis')
+                for v_ont_ani_item in v_ont_ani_items:
+                    if v_ont_ani_item.name == data.data.v_ontani_ref:
+                        return self.get_device_id(v_ont_ani_item)
+                return None
+        return device_id
+
+    def get_parent_data(self, data):
+        if data is None:
+            return None
+        val = self.interface_stack[type(data)]
+        if val['parent'] is None:
+            return None
+        id_val = {}
+        count = 0
+        for key in val['parent_path_keys']:
+            id_val[count] = self.rgetattr(data, key)
+            count+=1
+        parent_path = val['parent_path'].format(*id_val.values())
+        try:
+            parent_data = self.core.get_proxy('/').get(parent_path)
+            return parent_data
+        except ValueError:
+            log.info('xpon-agent-warning-interface-cannot-get-parent', data=data)
+            return None
+
+    def rgetattr(self, obj, attr):
+        def _getattr(obj, name):
+            return getattr(obj, name)
+        return functools.reduce(_getattr, [obj]+attr.split('.'))
+
+    def is_valid_interface(self, data):
+        valid = False
+        for key in self.interfaces.keys():
+            valid |= isinstance(data, key)
+        return valid
+
+    def register_interface(self, device_id, path, update=True):
+        log.info('register-interface:', device_id=device_id, path=path)
+        try:
+            interface_proxy = self.core.get_proxy(path)
+            if update:
+                interface_proxy.register_callback(CallbackType.POST_UPDATE, self.update_interface, device_id)
+            else:
+                interface_proxy.register_callback(CallbackType.POST_ADD, self.create_interface, device_id)
+                interface_proxy.register_callback(CallbackType.POST_REMOVE, self.remove_interface, device_id)
+        except:
+            print "Unexpected error:", sys.exc_info()[0]
+
+    def unregister_interface(self, device_id, path, update=True):
+        log.info('unregister-interface:', device_id=device_id, path=path)
+        try:
+            interface_proxy = self.core.get_proxy(path)
+            if update:
+                interface_proxy.unregister_callback(CallbackType.POST_UPDATE, self.update_interface, device_id)
+            else:
+                interface_proxy.unregister_callback(CallbackType.POST_ADD, self.create_interface, device_id)
+                interface_proxy.unregister_callback(CallbackType.POST_REMOVE, self.remove_interface, device_id)
+        except:
+            print "Unexpected error:", sys.exc_info()[0]
+
+    def create_interface(self, data, device_id=None):
+        if device_id is None:
+            device_id = self.get_device_id(data)
+        if not self.is_valid_interface(data):
+            log.info('xpon-agent-create-interface-invalid-interface-type', type=type(data).__name__)
+            return
+        self.register_interface(device_id=device_id, path=self.get_interface_path(data))
+        if device_id is not None:
+            if(isinstance(data, ChannelterminationConfig)):
+                self.create_channel_termination(data, device_id)
+            elif(isinstance(data, VOntaniConfig)):
+                self.create_v_ont_ani(data, device_id)
+            else:
+                log.info('xpon-agent-create-interface:', device_id=device_id, data=data)
+                device, adapter_agent = self.get_device_adapter_agent(device_id)
+                adapter_agent.create_interface(device=device, data=data)
+
+    def update_interface(self, data, device_id):
+        if not self.is_valid_interface(data):
+            log.info('xpon-agent-update-interface-invalid-interface-type', type=type(data).__name__)
+            return
+        if device_id is None:
+            device_id = self.get_device_id(data)
+        if device_id is not None:
+            # This can be any interface
+            device, adapter_agent = self.get_device_adapter_agent(device_id)
+            interfaces = []
+            ont_interfaces = []
+            parent_data = self.get_parent_data(data)
+            pre_parent_data = self.get_parent_data(self.preData)
+            if parent_data is not None and pre_parent_data is None:
+                while parent_data is not None:
+                    interfaces.insert(0, parent_data)
+                    parent_data = self.get_parent_data(parent_data)
+
+                for interface in interfaces:
+                    log.info('xpon-agent-creating-interface', device_id=device_id, data=interface)
+                    adapter_agent.create_interface(device=device, data=interface)
+
+                venet_items = self.core.get_proxy('/').get('/v_enets')
+                for venet in venet_items:
+                    if device_id == self.get_device_id(venet):
+                        ont_interfaces.insert(0, venet)
+                        parent_data = self.get_parent_data(venet)
+                        while not isinstance(parent_data, ChannelpairConfig):
+                            ont_interfaces.insert(0, parent_data)
+                            parent_data = self.get_parent_data(parent_data)
+
+                        for ont_interface in ont_interfaces:
+                            log.info('xpon-agent-creating-ont-interface', device_id=device_id, data=ont_interface)
+                            adapter_agent.create_interface(device=device, data=ont_interface)
+
+            log.info('xpon-agent-updating-interface', device_id=device_id, data=data)
+            adapter_agent.update_interface(device=device, data=data)
+
+    def remove_interface(self, data, device_id=None):
+        if device_id is None:
+            device_id = self.get_device_id(data)
+        if not self.is_valid_interface(data):
+            log.info('xpon-agent-remove-interface-invalid-interface-type', type=type(data).__name__)
+            return
+        log.info('xpon-agent-remove-interface:', device_id=device_id, data=data)
+        if device_id is not None:
+            if(isinstance(data, ChannelterminationConfig)):
+                self.remove_channel_termination(data, device_id)
+            else:
+                device, adapter_agent = self.get_device_adapter_agent(device_id)
+                adapter_agent.remove_interface(device=device, data=data)
+                if isinstance(data, VOntaniConfig):
+                    self.delete_onu_device(device_id=device_id, v_ont_ani=data)
+
+    def create_channel_termination(self, data, device_id):
+        device, adapter_agent = self.get_device_adapter_agent(device_id)
+        channel_pair = self.get_parent_data(data)
+        channel_part = self.get_parent_data(channel_pair)
+        channel_group = self.get_parent_data(channel_part)
+
+        if channel_group:
+            log.info('xpon-agent-creating-channel-group', device_id=device_id, data=channel_group)
+            adapter_agent.create_interface(device=device, data=channel_group)
+        if channel_part:
+            log.info('xpon-agent-creating-channel-partition:', device_id=device_id, data=channel_part)
+            adapter_agent.create_interface(device=device, data=channel_part)
+        if channel_pair:
+            log.info('xpon-agent-creating-channel-pair:', device_id=device_id, data=channel_pair)
+            adapter_agent.create_interface(device=device, data=channel_pair)
+        log.info('xpon-agent-creating-channel-termination:', device_id=device_id, data=data)
+        adapter_agent.create_interface(device=device, data=data)
+        # Take care of ont ani and v ont ani
+        vont_items = self.core.get_proxy('/').get('/v_ont_anis')
+        for vont in vont_items:
+            vont_id = self.get_device_id(vont)
+            if device_id == vont_id:
+                self.create_v_ont_ani(vont, device_id)
+
+    def create_v_ont_ani(self, data, device_id):
+        if not self.inReplay:
+           self.create_onu_device(device_id=device_id, v_ont_ani=data)
+        device, adapter_agent = self.get_device_adapter_agent(device_id)
+        venets = self.core.get_proxy('/').get('/v_enets')
+        log.info('xpon-agent-creating-vont-ani:', device_id=device_id, data=data)
+        adapter_agent.create_interface(device=device, data=data)
+
+        try:
+            ont_ani = self.core.get_proxy('/').get('/ont_anis/{}'.format(data.name))
+            log.info('xpon-agent-create-v-ont-ani-creating-ont-ani:', device_id=device_id, data=ont_ani)
+            adapter_agent.create_interface(device=device, data=ont_ani)
+        except KeyError:
+            log.info('xpon-agent-create-v-ont-ani-there-is-no-ont-ani-to-create')
+
+        for venet in venets:
+            if venet.data.v_ontani_ref == data.name:
+                log.info('xpon-agent-create-v-ont-ani-creating-v-enet:', device_id=device_id, data=venet)
+                adapter_agent.create_interface(device=device, data=venet)
+
+    def remove_channel_termination(self, data, device_id):
+        device, adapter_agent = self.get_device_adapter_agent(device_id)
+        log.info('xpon-agent-removing-channel-termination:', device_id=device_id, data=data)
+        adapter_agent.remove_interface(device=device, data=data)
+
+        if data.data.channelpair_ref:
+            channel_pair = self.get_parent_data(data)
+            log.info('xpon-agent-removing-channel-pair:', device_id=device_id, data=channel_pair)
+            adapter_agent.remove_interface(device=device, data=channel_pair)
+            # Remove vontani and ontani if it has reference to cpair
+            items = self.core.get_proxy('/').get('/v_ont_anis')
+            for item in items:
+                if (item.data.preferred_chanpair == channel_pair.name or \
+                    item.data.protection_chanpair == channel_pair.name):
+                    log.info('xpon-agent-removing-vont-ani:', device_id=device_id, data=item)
+                    adapter_agent.remove_interface(device=device, data=item)
+                    self.delete_onu_device(device_id=device_id, v_ont_ani=item)
+
+                    venets_items = self.core.get_proxy('/').get('/v_enets')
+                    for venet in venets_items:
+                        if item.name == venet.data.v_ontani_ref:
+                            log.info('xpon-agent-removing-v-enet:', device_id=device_id, data=venet)
+                            adapter_agent.remove_interface(device=device, data=venet)
+
+                    ontani_items = self.core.get_proxy('/').get('/ont_anis')
+                    for ontani_item in ontani_items:
+                        if ontani_item.name == item.name:
+                            log.info('xpon-agent-removing-ont-ani:', device_id=device_id, data=ontani_item)
+                            adapter_agent.remove_interface(device=device, data=ontani_item)
+            # Remove cpart if exists
+            if channel_pair.data.channelpartition_ref:
+                channel_part = self.get_parent_data(channel_pair)
+                log.info('xpon-agent-removing-channel-partition:', device_id=device_id, data=channel_part)
+                adapter_agent.remove_interface(device=device, data=channel_part)
+
+                if channel_part.data.channelgroup_ref:
+                    channel_group = self.get_parent_data(channel_part)
+                    log.info('xpon-agent-removing-channel-group:', device_id=device_id, data=channel_group)
+                    adapter_agent.remove_interface(device=device, data=channel_group)
+
+    def replay_interface(self, device_id):
+        self.inReplay = True
+        ct_items = self.core.get_proxy('/').get('/devices/{}/channel_terminations'.format(device_id))
+        for ct in ct_items:
+            self.create_interface(data=ct, device_id=device_id)
+        self.inReplay = False
+
+    def get_port_num(self, device_id, label):
+        log.info('get-port-num:', label=label, device_id=device_id)
+        ports = self.core.get_proxy('/').get('/devices/{}/ports'.format(device_id))
+        log.info('get-port-num:', label=label, device_id=device_id, ports=ports)
+        for port in ports:
+            if port.label == label:
+                return port.port_no
+        return 0
+
+    def create_onu_device(self, device_id, v_ont_ani):
+        log.info('create-onu-device', v_ont_ani=v_ont_ani, device=device_id)
+        device, adapter_agent = self.get_device_adapter_agent(device_id)
+        parent_chnl_pair_id = self.get_port_num(device.id, v_ont_ani.data.preferred_chanpair)
+        log.info('create-onu-device:', parent_chnl_pair_id=parent_chnl_pair_id)
+        onu_type = v_ont_ani.data.expected_serial_number[:4]
+        proxy_address = Device.ProxyAddress(device_id=device.id, channel_id=parent_chnl_pair_id,
+                                           onu_id=v_ont_ani.data.onu_id, onu_session_id=v_ont_ani.data.onu_id)
+        adapter_agent.child_device_detected(parent_device_id=device.id, parent_port_no=parent_chnl_pair_id,
+                                            child_device_type=onu_type,
+                                            proxy_address=proxy_address,
+                                            root=True, serial_number=v_ont_ani.data.expected_serial_number,
+                                            admin_state=AdminState.ENABLED if v_ont_ani.interface.enabled else AdminState.DISABLED
+                                            )
+        return
+
+    def delete_onu_device(self, device_id, v_ont_ani):
+        log.info('delete-onu-device', v_ont_ani=v_ont_ani, device=device_id)
+        device, adapter_agent = self.get_device_adapter_agent(device_id)
+        onu_device = adapter_agent.get_child_device(parent_device_id=device_id, serial_number=v_ont_ani.data.expected_serial_number)
+        if onu_device is not None:
+            adapter_agent.delete_child_device(device_id, onu_device.id)
+        return
diff --git a/voltha/core/xpon_handler.py b/voltha/core/xpon_handler.py
new file mode 100644
index 0000000..6e461ff
--- /dev/null
+++ b/voltha/core/xpon_handler.py
@@ -0,0 +1,812 @@
+# Copyright 2017 the original author or authors.
+#
+# 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 Queue import Empty as QueueEmpty
+
+import structlog
+import re
+from uuid import uuid4
+
+from google.protobuf.empty_pb2 import Empty
+from grpc import StatusCode
+
+from voltha.protos.bbf_fiber_base_pb2 import \
+    AllChannelgroupConfig, ChannelgroupConfig, \
+    AllChannelpairConfig, ChannelpairConfig, \
+    AllChannelpartitionConfig, ChannelpartitionConfig, \
+    AllChannelterminationConfig, ChannelterminationConfig, \
+    AllOntaniConfig, OntaniConfig, AllVOntaniConfig , VOntaniConfig, \
+    AllVEnetConfig, VEnetConfig
+
+from voltha.protos.device_pb2 import Device
+from voltha.protos.common_pb2 import AdminState
+
+from requests.api import request
+
+log = structlog.get_logger()
+
+
+class XponHandler(object):
+    def __init__(self, core):
+        self.core = core
+        self.root = None
+
+    def start(self, root):
+        log.debug('starting xpon_handler')
+        self.root = root
+
+    def get_all_channel_group_config(self, request, context):
+        log.info('grpc-request', request=request)
+        items = self.root.get('/channel_groups')
+        return AllChannelgroupConfig(channelgroup_config=items)
+
+    def create_channel_group(self, request, context):
+        log.info('grpc-request', request=request)
+
+        try:
+            assert isinstance(request, ChannelgroupConfig)
+            assert self.validate_interface(request, context)
+            log.debug('creating-channel-group', name=request.name)
+            self.root.add('/channel_groups', request)
+
+            return Empty()
+        except AssertionError, e:
+            return Empty()
+        except ValueError:
+            context.set_details(
+                'Duplicated channel group \'{}\' cannot be created'.format(request.name))
+            context.set_code(StatusCode.INVALID_ARGUMENT)
+            return Empty()
+
+    def update_channel_group(self, request, context):
+        log.info('grpc-request', request=request)
+
+        if '/' in request.name:
+            context.set_details(
+                'Malformed name \'{}\''.format(request.name))
+            context.set_code(StatusCode.INVALID_ARGUMENT)
+            return ChannelgroupConfig()
+
+        try:
+            assert isinstance(request, ChannelgroupConfig)
+            assert self.validate_interface(request, context)
+
+            path = '/channel_groups/{}'.format(request.name)
+            log.debug('updating-channel-group', name=request.name)
+            self.root.update(path, request, strict=True)
+            return Empty()
+
+        except AssertionError, e:
+            return Empty()
+
+        except KeyError:
+            context.set_details(
+                    'channel group \'{}\' not found'.format(request.name))
+            context.set_code(StatusCode.NOT_FOUND)
+            return Empty()
+
+    def delete_channel_group(self, request, context):
+        log.info('grpc-request', request=request)
+
+        if '/' in request.name:
+            context.set_details(
+                'Malformed name \'{}\''.format(request.name))
+            context.set_code(StatusCode.INVALID_ARGUMENT)
+            return Empty()
+
+        try:
+            assert isinstance(request, ChannelgroupConfig)
+            known_channel_group_ref = dict(
+                (dt.data.channelgroup_ref, dt) for dt in self.root.get('/channel_partitions'))
+            known_channel_group_ref_1 = dict(
+                (dt.data.channelgroup_ref, dt) for dt in self.root.get('/channel_pairs'))
+            reference = "channel partition"
+            assert request.name not in known_channel_group_ref
+            reference = "channel pair"
+            assert request.name not in known_channel_group_ref_1
+            path = '/channel_groups/{}'.format(request.name)
+            log.debug('removing-channel-group', name=request.name)
+            self.root.remove(path)
+
+            return Empty()
+
+        except AssertionError:
+            context.set_details(
+                'The channel group -- \'{}\' is referenced by {}'.format(request.name, reference))
+            context.set_code(StatusCode.INVALID_ARGUMENT)
+            return Empty()
+
+        except KeyError:
+            context.set_details(
+                'channel group \'{}\' not found'.format(request.name))
+            context.set_code(StatusCode.NOT_FOUND)
+            return Empty()
+
+    def get_all_channel_partition_config(self, request, context):
+        log.info('grpc-request', request=request)
+        items = self.root.get('/channel_partitions')
+        return AllChannelpartitionConfig(channelpartition_config=items)
+
+    def create_channel_partition(self, request, context):
+        log.info('grpc-request', request=request)
+
+        try:
+            assert isinstance(request, ChannelpartitionConfig)
+            assert self.validate_interface(request, context)
+            log.debug('creating-channel-partition', name=request.name)
+            self.root.add('/channel_partitions', request)
+
+            return Empty()
+        except AssertionError, e:
+            return Empty()
+        except ValueError:
+            context.set_details(
+                'Duplicated channel partition \'{}\' cannot be created'.format(request.name))
+            context.set_code(StatusCode.INVALID_ARGUMENT)
+            return Empty()
+
+    def update_channel_partition(self, request, context):
+        log.info('grpc-request', request=request)
+
+        if '/' in request.name:
+            context.set_details(
+                'Malformed name \'{}\''.format(request.name))
+            context.set_code(StatusCode.INVALID_ARGUMENT)
+            return ChannelpartitionConfig()
+
+        try:
+            assert isinstance(request, ChannelpartitionConfig)
+            assert self.validate_interface(request, context)
+
+            path = '/channel_partitions/{}'.format(request.name)
+            log.debug('updating-channel-partition', name=request.name)
+            self.root.update(path, request, strict=True)
+            return Empty()
+
+        except AssertionError, e:
+            return Empty()
+
+        except KeyError:
+            context.set_details(
+                    'channel partition \'{}\' not found'.format(request.name))
+            context.set_code(StatusCode.NOT_FOUND)
+            return Empty()
+
+    def delete_channel_partition(self, request, context):
+        log.info('grpc-request', request=request)
+
+        if '/' in request.name:
+            context.set_details(
+                'Malformed name \'{}\''.format(request.name))
+            context.set_code(StatusCode.INVALID_ARGUMENT)
+            return Empty()
+
+        try:
+            assert isinstance(request, ChannelpartitionConfig)
+            known_channel_partition_ref = dict(
+                (dt.data.channelpartition_ref, dt) for dt in self.root.get('/channel_pairs'))
+            known_channel_partition_ref_1 = dict(
+                (dt.data.parent_ref, dt) for dt in self.root.get('/v_ont_anis'))
+            reference = "channel pair"
+            assert request.name not in known_channel_partition_ref
+            reference = "vontani"
+            assert request.name not in known_channel_partition_ref_1
+            path = '/channel_partitions/{}'.format(request.name)
+            log.debug('removing-channel-partition', name=request.name)
+            self.root.remove(path)
+
+            return Empty()
+
+        except AssertionError:
+            context.set_details(
+                'The channel partition -- \'{}\' is referenced by {}'.format(request.name, reference))
+            context.set_code(StatusCode.INVALID_ARGUMENT)
+            return Empty()
+
+        except KeyError:
+            context.set_details(
+                'channel partition \'{}\' not found'.format(request.name))
+            context.set_code(StatusCode.NOT_FOUND)
+            return Empty()
+
+    def get_all_channel_pair_config(self, request, context):
+        log.info('grpc-request', request=request)
+        items = self.root.get('/channel_pairs')
+        return AllChannelpairConfig(channelpair_config=items)
+
+    def create_channel_pair(self, request, context):
+        log.info('grpc-request', request=request)
+
+        try:
+            assert isinstance(request, ChannelpairConfig)
+            assert self.validate_interface(request, context)
+            log.debug('creating-channel-pair', name=request.name)
+            self.root.add('/channel_pairs', request)
+
+            return Empty()
+        except AssertionError, e:
+            return Empty()
+        except ValueError:
+            context.set_details(
+                'Duplicated channel pair \'{}\' cannot be created'.format(request.name))
+            context.set_code(StatusCode.INVALID_ARGUMENT)
+            return Empty()
+
+    def update_channel_pair(self, request, context):
+        log.info('grpc-request', request=request)
+
+        if '/' in request.name:
+            context.set_details(
+                'Malformed name \'{}\''.format(request.name))
+            context.set_code(StatusCode.INVALID_ARGUMENT)
+            return ChannelpairConfig()
+
+        try:
+            assert isinstance(request, ChannelpairConfig)
+            assert self.validate_interface(request, context)
+
+            path = '/channel_pairs/{}'.format(request.name)
+            log.debug('updating-channel-pair', name=request.name)
+            self.root.update(path, request, strict=True)
+            return Empty()
+
+        except AssertionError, e:
+            return Empty()
+
+        except KeyError:
+            context.set_details(
+                    'channel pair \'{}\' not found'.format(request.name))
+            context.set_code(StatusCode.NOT_FOUND)
+            return Empty()
+
+    def delete_channel_pair(self, request, context):
+        log.info('grpc-request', request=request)
+
+        if '/' in request.name:
+            context.set_details(
+                'Malformed name \'{}\''.format(request.name))
+            context.set_code(StatusCode.INVALID_ARGUMENT)
+            return Empty()
+
+        try:
+            assert isinstance(request, ChannelpairConfig)
+            device_items = self.root.get('/devices')
+            for device_item in device_items:
+                known_channel_pair_ref = dict(
+                    (dt.data.channelpair_ref, dt) for dt in self.root.get(
+                        '/devices/{}/channel_terminations'.format(device_item.id)))
+                assert request.name not in known_channel_pair_ref
+            path = '/channel_pairs/{}'.format(request.name)
+            log.debug('removing-channel-pair', name=request.name)
+            self.root.remove(path)
+
+            return Empty()
+
+        except AssertionError:
+            context.set_details(
+                'The channel pair -- \'{}\' is referenced by channel termination'.format(request.name))
+            context.set_code(StatusCode.INVALID_ARGUMENT)
+            return Empty()
+
+        except KeyError:
+            context.set_details(
+                'channel pair \'{}\' not found'.format(request.name))
+            context.set_code(StatusCode.NOT_FOUND)
+            return Empty()
+
+    def get_all_channel_termination_config(self, request, context):
+        log.info('grpc-request', request=request)
+        if '/' in request.id:
+            context.set_details(
+                'Malformed device id \'{}\''.format(request.id))
+            context.set_code(StatusCode.INVALID_ARGUMENT)
+            return AllChannelterminationConfig()
+
+        try:
+            items = self.root.get(
+                '/devices/{}/channel_terminations'.format(request.id))
+            return AllChannelterminationConfig(channeltermination_config=items)
+        except KeyError:
+            context.set_details(
+                'Device \'{}\' not found'.format(request.id))
+            context.set_code(StatusCode.NOT_FOUND)
+            return AllChannelterminationConfig()
+
+    def create_channel_termination(self, request, context):
+        log.info('grpc-request', request=request)
+
+        try:
+            assert isinstance(request, ChannelterminationConfig)
+            assert self.validate_interface(request, context)
+            #device = self.root.get('/devices/{}'.format(request.id))
+        except AssertionError, e:
+            return Empty()
+        except KeyError:
+            context.set_details(
+                'Device \'{}\' not found'.format(request.id))
+            context.set_code(StatusCode.NOT_FOUND)
+            return Empty()
+        try:
+            path = '/devices/{}/channel_terminations'.format(request.id)
+            log.debug('creating-channel-termination', name=request.name)
+            self.root.add(path, request)
+            return Empty()
+        except KeyError:
+            context.set_details(
+                'Device \'{}\' not activated'.format(request.id))
+            context.set_code(StatusCode.NOT_FOUND)
+            return Empty()
+        except ValueError:
+            context.set_details(
+                'Duplicated channel termination \'{}\' cannot be created'.format(request.name))
+            context.set_code(StatusCode.INVALID_ARGUMENT)
+            return Empty()
+
+    def update_channel_termination(self, request, context):
+        log.info('grpc-request', request=request)
+
+        if '/' in request.name:
+            context.set_details(
+                'Malformed name \'{}\''.format(request.name))
+            context.set_code(StatusCode.INVALID_ARGUMENT)
+            return ChannelterminationConfig()
+
+        try:
+            assert isinstance(request, ChannelterminationConfig)
+            assert self.validate_interface(request, context)
+        except AssertionError, e:
+            return Empty()
+        except KeyError:
+            context.set_details(
+                'Device \'{}\' not found'.format(request.id))
+            context.set_code(StatusCode.NOT_FOUND)
+            return Empty()
+
+        try:
+            path = '/devices/{}/channel_terminations/{}'.format(request.id, request.name)
+            log.debug('updating-channel-termination', name=request.name)
+            self.root.update(path, request, strict=True)
+            return Empty()
+
+        except KeyError:
+            context.set_details(
+                'channel termination \'{}\' not found'.format(request.name))
+            context.set_code(StatusCode.NOT_FOUND)
+            return Empty()
+
+    def delete_channel_termination(self, request, context):
+        log.info('grpc-request', request=request)
+
+        if '/' in request.id:
+            context.set_details(
+                'Malformed device id \'{}\''.format(request.id))
+            context.set_code(StatusCode.INVALID_ARGUMENT)
+            return Empty()
+
+        if '/' in request.name:
+            context.set_details(
+                'Malformed name \'{}\''.format(request.name))
+            context.set_code(StatusCode.INVALID_ARGUMENT)
+            return Empty()
+
+        try:
+            assert isinstance(request, ChannelterminationConfig)
+        except AssertionError:
+            context.set_details(
+                'Instance is not of channel termination')
+            context.set_code(StatusCode.INVALID_ARGUMENT)
+            return Empty()
+        except KeyError:
+            context.set_details(
+                'Device \'{}\' not found'.format(request.id))
+            context.set_code(StatusCode.NOT_FOUND)
+            return Empty()
+        try:
+            path = '/devices/{}/channel_terminations/{}'.format(request.id, request.name)
+        except KeyError:
+            context.set_details(
+                'channel termination \'{}\' not found'.format(request.name))
+            context.set_code(StatusCode.NOT_FOUND)
+            return Empty()
+        try:
+            log.debug('removing-channel-termination', name=request.name)
+            self.root.remove(path)
+            return Empty()
+
+        except KeyError:
+            context.set_details(
+                'Could not delete channel termination \'{}\''.format(request.name))
+            context.set_code(StatusCode.INVALID_ARGUMENT)
+            return Empty()
+
+    def get_all_ont_ani_config(self, request, context):
+        log.info('grpc-request', request=request)
+        items = self.root.get('/ont_anis')
+        return AllOntaniConfig(ontani_config=items)
+
+    def create_ont_ani(self, request, context):
+        log.info('grpc-request', request=request)
+
+        try:
+            assert isinstance(request, OntaniConfig)
+            assert self.validate_interface(request, context)
+            log.debug('creating-ont-ani', name=request.name)
+            self.root.add('/ont_anis', request)
+            return Empty()
+        except AssertionError, e:
+            return Empty()
+        except KeyError:
+            context.set_details(
+                'Cannot create ontani \'{}\''.format(request.name))
+            context.set_code(StatusCode.NOT_FOUND)
+            return Empty()
+        except ValueError:
+            context.set_details(
+                'Duplicated ontani \'{}\' cannot be created'.format(request.name))
+            context.set_code(StatusCode.INVALID_ARGUMENT)
+            return Empty()
+
+    def update_ont_ani(self, request, context):
+        log.info('grpc-request', request=request)
+
+        if '/' in request.name:
+            context.set_details(
+                'Malformed name \'{}\''.format(request.name))
+            context.set_code(StatusCode.INVALID_ARGUMENT)
+            return OntaniConfig()
+
+        try:
+            assert isinstance(request, OntaniConfig)
+            assert self.validate_interface(request, context)
+
+            path = '/ont_anis/{}'.format(request.name)
+            log.debug('updating-ont-ani', name=request.name)
+            self.root.update(path, request, strict=True)
+            return Empty()
+
+        except AssertionError, e:
+            return Empty()
+
+        except KeyError:
+            context.set_details(
+                'ontani \'{}\' not found'.format(request.name))
+            context.set_code(StatusCode.NOT_FOUND)
+            return Empty()
+
+    def delete_ont_ani(self, request, context):
+        log.info('grpc-request', request=request)
+
+        if '/' in request.name:
+            context.set_details(
+                'Malformed name \'{}\''.format(request.name))
+            context.set_code(StatusCode.INVALID_ARGUMENT)
+            return Empty()
+
+        try:
+            assert isinstance(request, OntaniConfig)
+
+            path = '/ont_anis/{}'.format(request.name)
+            log.debug('removing-ont-ani', name=request.name)
+            self.root.remove(path)
+            return Empty()
+
+        except AssertionError:
+            context.set_details(
+                'Instance is not of ont ani')
+            context.set_code(StatusCode.INVALID_ARGUMENT)
+            return Empty()
+
+        except KeyError:
+            context.set_details(
+                'ontani \'{}\' not found'.format(request.name))
+            context.set_code(StatusCode.NOT_FOUND)
+            return Empty()
+
+    def get_all_v_ont_ani_config(self, request, context):
+        log.info('grpc-request', request=request)
+        items = self.root.get('/v_ont_anis')
+        return AllVOntaniConfig(v_ontani_config=items)
+
+    def create_v_ont_ani(self, request, context):
+        log.info('grpc-request', request=request)
+
+        try:
+            assert isinstance(request, VOntaniConfig)
+            assert self.validate_interface(request, context)
+            log.debug('creating-vont-ani', name=request.name)
+            self.root.add('/v_ont_anis', request)
+            return Empty()
+        except AssertionError, e:
+            return Empty()
+        except KeyError:
+            context.set_details(
+                'Cannot create vontani \'{}\''.format(request.name))
+            context.set_code(StatusCode.NOT_FOUND)
+            return Empty()
+        except ValueError:
+            context.set_details(
+                'Duplicated vontani \'{}\' cannot be created'.format(request.name))
+            context.set_code(StatusCode.INVALID_ARGUMENT)
+            return Empty()
+
+    def update_v_ont_ani(self, request, context):
+        log.info('grpc-request', request=request)
+
+        if '/' in request.name:
+            context.set_details(
+                'Malformed name \'{}\''.format(request.name))
+            context.set_code(StatusCode.INVALID_ARGUMENT)
+            return VOntaniConfig()
+
+        try:
+            assert isinstance(request, VOntaniConfig)
+            assert self.validate_interface(request, context)
+
+            path = '/v_ont_anis/{}'.format(request.name)
+            log.debug('updating-vont-ani', name=request.name)
+            self.root.update(path, request, strict=True)
+            return Empty()
+
+        except AssertionError, e:
+            return Empty()
+
+        except KeyError:
+            context.set_details(
+                'vontani \'{}\' not found'.format(request.name))
+            context.set_code(StatusCode.NOT_FOUND)
+            return Empty()
+
+    def delete_v_ont_ani(self, request, context):
+        log.info('grpc-request', request=request)
+
+        if '/' in request.name:
+            context.set_details(
+                'Malformed name \'{}\''.format(request.name))
+            context.set_code(StatusCode.INVALID_ARGUMENT)
+            return Empty()
+
+        try:
+            assert isinstance(request, VOntaniConfig)
+            known_v_ont_ani_ref = dict(
+                (dt.data.v_ontani_ref, dt) for dt in self.root.get('/v_enets'))
+            assert request.name not in known_v_ont_ani_ref
+
+            path = '/v_ont_anis/{}'.format(request.name)
+            log.debug('removing-vont-ani', name=request.name)
+            self.root.remove(path)
+
+            return Empty()
+
+        except AssertionError:
+            context.set_details(
+                'The vont ani -- \'{}\' is referenced by venet'.format(request.name))
+            context.set_code(StatusCode.INVALID_ARGUMENT)
+            return Empty()
+
+        except KeyError:
+            context.set_details(
+                'vontani \'{}\' not found'.format(request.name))
+            context.set_code(StatusCode.NOT_FOUND)
+            return Empty()
+
+    def get_all_v_enet_config(self, request, context):
+        log.info('grpc-request', request=request)
+        items = self.root.get('/v_enets')
+        return AllVEnetConfig(v_enet_config=items)
+
+    def create_v_enet(self, request, context):
+        log.info('grpc-request', request=request)
+
+        try:
+            assert isinstance(request, VEnetConfig)
+            assert self.validate_interface(request, context)
+            log.debug('creating-venet', name=request.name)
+            self.root.add('/v_enets', request)
+            return Empty()
+        except AssertionError, e:
+            return Empty()
+        except KeyError:
+            context.set_details(
+                'Cannot create venet \'{}\''.format(request.name))
+            context.set_code(StatusCode.NOT_FOUND)
+            return Empty()
+        except ValueError:
+            context.set_details(
+                'Duplicated venet \'{}\' cannot be created'.format(request.name))
+            context.set_code(StatusCode.INVALID_ARGUMENT)
+            return Empty()
+
+    def update_v_enet(self, request, context):
+        log.info('grpc-request', request=request)
+
+        if '/' in request.name:
+            context.set_details(
+                'Malformed name \'{}\''.format(request.name))
+            context.set_code(StatusCode.INVALID_ARGUMENT)
+            return VEnetConfig()
+
+        try:
+            assert isinstance(request, VEnetConfig)
+            assert self.validate_interface(request, context)
+
+            path = '/v_enets/{}'.format(request.name)
+            log.debug('updating-venet', name=request.name)
+            self.root.update(path, request, strict=True)
+            return Empty()
+
+        except AssertionError, e:
+            return Empty()
+
+        except KeyError:
+            context.set_details(
+                'venet \'{}\' not found'.format(request.name))
+            context.set_code(StatusCode.NOT_FOUND)
+            return Empty()
+
+    def delete_v_enet(self, request, context):
+        log.info('grpc-request', request=request)
+
+        if '/' in request.name:
+            context.set_details(
+                'Malformed name \'{}\''.format(request.name))
+            context.set_code(StatusCode.INVALID_ARGUMENT)
+            return Empty()
+
+        try:
+            assert isinstance(request, VEnetConfig)
+            #assert device.admin_state == AdminState.DISABLED, \
+                #'Device to delete cannot be ' \
+                #'in admin state \'{}\''.format(device.admin_state)
+            path = '/v_enets/{}'.format(request.name)
+            log.debug('removing-venet', name=request.name)
+            self.root.remove(path)
+            return Empty()
+
+        except AssertionError:
+            context.set_details(
+                'Instance is not of venet')
+            context.set_code(StatusCode.INVALID_ARGUMENT)
+            return Empty()
+
+        except KeyError:
+            context.set_details(
+                'venet \'{}\' not found'.format(request.name))
+            context.set_code(StatusCode.NOT_FOUND)
+            return Empty()
+
+    def validate_interface(self, request, context):
+        try:
+            if(isinstance(request, ChannelgroupConfig)):
+                assert isinstance(request, ChannelgroupConfig)
+                channelgroup = request
+                assert channelgroup.name != '', 'Channel Group name is mandatory'
+                assert 0 <= channelgroup.data.polling_period <= 864000, \
+                    'Channel Group polling period must be in range of [1, 864000]'
+                return True
+            elif(isinstance(request, ChannelpartitionConfig)):
+                assert isinstance(request, ChannelpartitionConfig)
+                channelpartition = request
+                assert channelpartition.name != '', 'Channel Partition name is mandatory'
+
+                assert channelpartition.data.channelgroup_ref != '', \
+                    'Channel Partition must reference a channel group'
+                assert self.get_ref_data(request, context, "channel_groups", request.data.channelgroup_ref), \
+                    'Reference to channel group -- \'{}\' not found'.format(request.data.channelgroup_ref)
+
+                assert 0 <= channelpartition.data.closest_ont_distance <= 40, \
+                    'Channel Partition closest ont distance must be in range of [0, 40]'
+
+                assert channelpartition.data.differential_fiber_distance == 0 or \
+                    channelpartition.data.differential_fiber_distance == 20 or \
+                    channelpartition.data.differential_fiber_distance == 34 or \
+                    channelpartition.data.differential_fiber_distance == 40, \
+                    'Channel Partition differential fiber distance must be [20 | 34 | 40]'
+                return True
+            elif(isinstance(request, ChannelpairConfig)):
+                assert isinstance(request, ChannelpairConfig)
+                channelpair = request
+                channelpair_type = ["channelpair", "channelpair_xgs"]
+                channelpair_speed_type = ["unplanned_cp_speed", "down_10_up_10", "down_10_up_2_5", "down_2_5_up_2_5"]
+                assert channelpair.name != '', 'Channel Pair name is mandatory'
+
+                if channelpair.data.channelgroup_ref:
+                    assert self.get_ref_data(request, context, "channel_groups", request.data.channelgroup_ref), \
+                        'Reference to channel group -- \'{}\' not found'\
+                        .format(request.data.channelgroup_ref)
+                if channelpair.data.channelpartition_ref:
+                    assert self.get_ref_data(request, context, "channel_partitions", request.data.channelpartition_ref), \
+                        'Reference to channel partition -- \'{}\' not found'\
+                        .format(request.data.channelpartition_ref)
+
+                assert channelpair.data.channelpair_type != '', 'Channel Pair type is mandatory'
+                assert channelpair.data.channelpair_type in channelpair_type, \
+                    'Invalid value for Channel Pair type \'{}\''.format(channelpair.data.channelpair_type)
+                assert channelpair.data.channelpair_linerate in channelpair_speed_type, \
+                    'Invalid value for Channel Pair linerate \'{}\''.format(channelpair.data.channelpair_linerate)
+                return True
+            elif(isinstance(request, ChannelterminationConfig)):
+                assert isinstance(request, ChannelterminationConfig)
+                channeltermin = request
+                assert '/' not in channeltermin.id, 'Malformed device id \'{}\''.format(request.id)
+                assert channeltermin.id != '', 'Device ID is mandatory'
+                assert channeltermin.name != '', 'Channel Termination name is mandatory'
+
+                if channeltermin.data.channelpair_ref:
+                    assert self.get_ref_data(request, context, "channel_pairs", request.data.channelpair_ref), \
+                        'Reference to channel pair -- \'{}\' not found'.format(request.data.channelpair_ref)
+
+                assert 0 <= channeltermin.data.ber_calc_period <= 864000, \
+                    'Channel Termination ber calc period must be in range of [1, 864000]'
+                return True
+            elif(isinstance(request, OntaniConfig)):
+                assert isinstance(request, OntaniConfig)
+                ontani = request
+                assert ontani.name != '', 'OntAni name is mandatory'
+                return True
+            elif(isinstance(request, VOntaniConfig)):
+                assert isinstance(request, VOntaniConfig)
+                vontani = request
+                assert vontani.name != '', 'VOntAni name is mandatory'
+
+                if vontani.data.parent_ref:
+                    assert self.get_ref_data(request, context, "channel_partitions", request.data.parent_ref), \
+                        'Reference to channel partition -- \'{}\' not found'.format(request.data.parent_ref)
+                if vontani.data.preferred_chanpair:
+                    assert self.get_ref_data(request, context, "channel_pairs", request.data.preferred_chanpair), \
+                        'Preferred channel pair -- \'{}\' not found'.format(request.data.preferred_chanpair)
+                if vontani.data.protection_chanpair:
+                    assert self.get_ref_data(request, context, "channel_pairs", request.data.protection_chanpair), \
+                        'Protection channel pair -- \'{}\' not found'.format(request.data.protection_chanpair)
+
+                assert 0 <= len(vontani.data.expected_registration_id) <= 36, \
+                    'VOnt Ani expected registration id string length must be in range of [0, 36]'
+                assert 0 <= vontani.data.onu_id <= 1020, \
+                    'VOnt Ani ONU id must be in range of [0, 1020]'
+
+                items = self.root.get('/v_ont_anis')
+                for item in items:
+                    if item.data.parent_ref == vontani.data.parent_ref or \
+                        item.data.preferred_chanpair == vontani.data.preferred_chanpair or \
+                        item.data.protection_chanpair == vontani.data.protection_chanpair:
+                        assert item.data.onu_id != vontani.data.onu_id, \
+                            'VOnt Ani ONU id -- \'{}\' already exists, but must be unique within channel group'.format(vontani.data.onu_id)
+                return True
+            elif(isinstance(request, VEnetConfig)):
+                assert isinstance(request, VEnetConfig)
+                venet = request
+                assert venet.name != '', 'VEnet name is mandatory'
+
+                if venet.data.v_ontani_ref:
+                    assert self.get_ref_data(request, context, "v_ont_anis", venet.data.v_ontani_ref), \
+                        'Reference to ont ani -- \'{}\' not found'.format(venet.data.v_ontani_ref)
+                return True
+            else:
+                return False
+        except AssertionError, e:
+            context.set_details(e.message)
+            context.set_code(StatusCode.INVALID_ARGUMENT)
+            return False
+
+    def get_ref_data(self, request, context, interface, reference):
+        depth = int(dict(context.invocation_metadata()).get('get-depth', 0))
+
+        try:
+            path = '/{}/'.format(interface)
+            self.root.get(path + reference, depth=depth)
+            log.info('reference-for-{}-found-\'{}\''.format(interface, reference))
+            return True
+
+        except KeyError:
+            log.info('reference-for-{}-not-found-\'{}\''.format(interface, reference))
+            return False
diff --git a/voltha/protos/bbf_fiber.proto b/voltha/protos/bbf_fiber.proto
new file mode 100644
index 0000000..65a3f78
--- /dev/null
+++ b/voltha/protos/bbf_fiber.proto
@@ -0,0 +1,14 @@
+/*
+TOP Level BBF Fiber proto
+*/
+
+syntax = "proto3";
+package bbf_fiber;
+import "bbf_fiber_base.proto";
+import "bbf_fiber_wavelength_profile_body.proto";
+import "bbf_fiber_channelgroup_body.proto";
+import "bbf_fiber_channelpartition_body.proto";
+import "bbf_fiber_channelpair_body.proto";
+import "bbf_fiber_channeltermination_body.proto";
+import "bbf_fiber_ontani_body.proto";
+import "bbf_fiber_v_ontani_body.proto";
diff --git a/voltha/protos/bbf_fiber_base.proto b/voltha/protos/bbf_fiber_base.proto
new file mode 100644
index 0000000..2c02171
--- /dev/null
+++ b/voltha/protos/bbf_fiber_base.proto
@@ -0,0 +1,111 @@
+syntax = "proto3";
+package bbf_fiber;
+
+import public "meta.proto";
+import "ietf_interfaces.proto";
+import "bbf_fiber_channelgroup_body.proto";
+import "bbf_fiber_channelpartition_body.proto";
+import "bbf_fiber_channelpair_body.proto";
+import "bbf_fiber_channeltermination_body.proto";
+import "bbf_fiber_ontani_body.proto";
+import "bbf_fiber_v_ontani_body.proto";
+import "bbf_fiber_v_enet_body.proto";
+
+message ChannelgroupConfig
+{
+	ietf_interfaces.Interface interface = 1;
+	ChannelgroupConfigData data = 2;
+	string name = 3;
+
+}
+
+message ChannelpartitionConfig
+{
+	ietf_interfaces.Interface interface = 1;
+	ChannelpartitionConfigData data = 2;
+	string name = 3;
+}
+
+message ChannelpairConfig
+{
+	ietf_interfaces.Interface interface = 1;
+	ChannelpairConfigData data = 2;
+	string name = 3;
+}
+message ChannelpairOper
+{
+	ietf_interfaces.Interface interface = 1;
+	ChannelpairOperData operdata = 2;
+	string name = 3;
+}
+
+message ChannelterminationConfig
+{
+	string id = 1; // To work around a chameleon POST bug
+	ietf_interfaces.Interface interface = 2;
+	ChannelterminationConfigData data = 3;
+	string name = 4;
+}
+message ChannelterminationOper
+{
+	ietf_interfaces.Interface interface = 1;
+	ChannelterminationOperData data = 2;
+	string name = 3;
+}
+
+
+message OntaniConfig
+{
+	ietf_interfaces.Interface interface = 1;
+	OntaniConfigData data = 2;
+	string name = 3;
+}
+message OntaniOper
+{
+	ietf_interfaces.Interface interface = 1;
+	OntaniOperData data = 2;
+	string name = 3;
+}
+
+message VOntaniConfig
+{
+	ietf_interfaces.Interface interface = 1;
+	VOntaniConfigData data = 2;
+	string name = 3;
+}
+
+message VEnetConfig
+{
+	ietf_interfaces.Interface interface = 1;
+	VEnetConfigData data = 2;
+	string name = 3;
+}
+
+message AllChannelgroupConfig
+{
+	repeated ChannelgroupConfig channelgroup_config = 1 [(voltha.child_node) = {key: "name"}];
+}
+message AllChannelpartitionConfig
+{
+	repeated ChannelpartitionConfig channelpartition_config = 1 [(voltha.child_node) = {key: "name"}];
+}
+message AllChannelpairConfig
+{
+	repeated ChannelpairConfig channelpair_config = 1 [(voltha.child_node) = {key: "name"}];
+}
+message AllChannelterminationConfig
+{
+	repeated ChannelterminationConfig channeltermination_config = 1 [(voltha.child_node) = {key: "name"}];
+}
+message AllOntaniConfig
+{
+	repeated OntaniConfig ontani_config = 1 [(voltha.child_node) = {key: "name"}];
+}
+message AllVOntaniConfig
+{
+	repeated VOntaniConfig v_ontani_config = 1 [(voltha.child_node) = {key: "name"}];
+}
+message AllVEnetConfig
+{
+	repeated VEnetConfig v_enet_config = 1 [(voltha.child_node) = {key: "name"}];
+}
diff --git a/voltha/protos/bbf_fiber_channelgroup_body.proto b/voltha/protos/bbf_fiber_channelgroup_body.proto
new file mode 100644
index 0000000..2eecc24
--- /dev/null
+++ b/voltha/protos/bbf_fiber_channelgroup_body.proto
@@ -0,0 +1,10 @@
+syntax = "proto3";
+package bbf_fiber;
+import public "meta.proto";
+import "bbf_fiber_types.proto";
+
+message ChannelgroupConfigData {
+	uint32 polling_period = 1;
+	bbf_fiber_types.RamanMitigationType raman_mitigation = 2;
+	string system_id = 3 ;
+}
diff --git a/voltha/protos/bbf_fiber_channelpair_body.proto b/voltha/protos/bbf_fiber_channelpair_body.proto
new file mode 100644
index 0000000..a66996b
--- /dev/null
+++ b/voltha/protos/bbf_fiber_channelpair_body.proto
@@ -0,0 +1,18 @@
+syntax = "proto3";
+package bbf_fiber;
+import "bbf_fiber_types.proto";
+
+message ChannelpairConfigData {
+    string channelgroup_ref = 1 ;
+    string channelpartition_ref = 2 ;
+    string channelpair_type = 3 ;
+    string channelpair_linerate = 4 ;
+    uint32 gpon_ponid_interval = 5 ;
+    bbf_fiber_types.PonIdOdnClassType gpon_ponid_odn_class = 6;
+}
+message ChannelpairOperData {
+    uint32 actual_downstream_lambda = 1 ;
+    bool primary_ct_assigned = 2 ;
+    bool secondary_ct_assigned = 3 ;
+}
+
diff --git a/voltha/protos/bbf_fiber_channelpartition_body.proto b/voltha/protos/bbf_fiber_channelpartition_body.proto
new file mode 100644
index 0000000..0134b35
--- /dev/null
+++ b/voltha/protos/bbf_fiber_channelpartition_body.proto
@@ -0,0 +1,12 @@
+syntax = "proto3";
+package bbf_fiber;
+import "bbf_fiber_types.proto";
+
+message ChannelpartitionConfigData {
+    string channelgroup_ref = 1 ;
+    bool fec_downstream = 2;
+    uint32 closest_ont_distance = 3;
+    uint32 differential_fiber_distance = 4;
+    bbf_fiber_types.AuthMethodType authentication_method = 5;
+    bool multicast_aes_indicator = 7;
+}
diff --git a/voltha/protos/bbf_fiber_channeltermination_body.proto b/voltha/protos/bbf_fiber_channeltermination_body.proto
new file mode 100644
index 0000000..2f921d5
--- /dev/null
+++ b/voltha/protos/bbf_fiber_channeltermination_body.proto
@@ -0,0 +1,21 @@
+syntax = "proto3";
+package bbf_fiber;
+
+message ChannelterminationConfigData {
+    string channelpair_ref = 1 ;
+    bool meant_for_type_b_primary_role = 2 ;
+    uint32 ngpon2_twdm_admin_label = 3 ;
+    uint32 ngpon2_ptp_admin_label = 4 ;
+    uint32 xgs_ponid = 5 ;
+    uint32 xgpon_ponid = 6 ;
+    string gpon_ponid = 7 ;
+    string pon_tag = 8 ;
+    uint32 ber_calc_period = 9 ;
+    string location = 10 ;
+    string url_to_reach = 11 ;
+}
+message ChannelterminationOperData {
+    string ponid_display = 1 ;
+    string type_b_state = 2 ;
+}
+
diff --git a/voltha/protos/bbf_fiber_ontani_body.proto b/voltha/protos/bbf_fiber_ontani_body.proto
new file mode 100644
index 0000000..35d1d69
--- /dev/null
+++ b/voltha/protos/bbf_fiber_ontani_body.proto
@@ -0,0 +1,11 @@
+syntax = "proto3";
+package bbf_fiber;
+
+message OntaniConfigData {
+        bool upstream_fec_indicator = 1 ;
+        bool mgnt_gemport_aes_indicator = 2 ;
+}
+message OntaniOperData {
+        uint32 onu_id = 1 ;
+        uint32 channel_partition_id = 2 ;
+}
diff --git a/voltha/protos/bbf_fiber_types.proto b/voltha/protos/bbf_fiber_types.proto
new file mode 100644
index 0000000..119ced0
--- /dev/null
+++ b/voltha/protos/bbf_fiber_types.proto
@@ -0,0 +1,50 @@
+syntax = "proto3";
+package bbf_fiber_types;
+
+enum AuthMethodType
+{
+    SERIAL_NUMBER               = 0;
+    LOID                        = 1;
+    REGISTRATION_ID             = 2;
+    OMCI                        = 3;
+    DOT1X                       = 4;
+
+}
+enum RamanMitigationType
+{
+    RAMAN_NONE                  = 0;
+    RAMAN_MILLER                = 1;
+    RAMAN_8B10B                 = 2;
+
+}
+enum PonIdOdnClassType
+{
+    CLASS_A                     = 0;
+    CLASS_B                     = 1;
+    CLASS_B_PLUS                = 2;
+    CLASS_C                     = 3;
+    CLASS_C_PLUS                = 4;
+    CLASS_AUTO                  = 255;
+}
+enum ChannelpairSpeedType
+{
+    UNPLANNED_CP_SPEED          = 0;
+    DOWN_10_UP_10               = 1;
+    DOWN_10_UP_2DOT5            = 2;
+    DOWN_2DOT5_UP_2DOT5         = 3;
+}
+enum ChannelpairType
+{
+    CHANNELPAIR                 = 0;
+    CHANNELPAIR_XGS             = 1;
+}
+enum TypeBRoleType
+{
+    PRIMARY                     = 0;
+    SECONDARY                   = 1;
+}
+enum TypeBRoleStateType
+{
+    ACTIVE                      = 0;
+    STANDBY                     = 1;
+}
diff --git a/voltha/protos/bbf_fiber_v_enet_body.proto b/voltha/protos/bbf_fiber_v_enet_body.proto
new file mode 100644
index 0000000..603668c
--- /dev/null
+++ b/voltha/protos/bbf_fiber_v_enet_body.proto
@@ -0,0 +1,6 @@
+syntax = "proto3";
+package bbf_fiber;
+
+message VEnetConfigData {
+	string v_ontani_ref = 1 ;
+}
diff --git a/voltha/protos/bbf_fiber_v_ontani_body.proto b/voltha/protos/bbf_fiber_v_ontani_body.proto
new file mode 100644
index 0000000..665caf6
--- /dev/null
+++ b/voltha/protos/bbf_fiber_v_ontani_body.proto
@@ -0,0 +1,12 @@
+syntax = "proto3";
+package bbf_fiber;
+
+message VOntaniConfigData {
+        string parent_ref = 1 ;
+        string expected_serial_number = 2 ;
+        string expected_registration_id = 3 ;
+        string preferred_chanpair = 4 ;
+        string protection_chanpair = 5 ;
+        uint32 upstream_channel_speed = 6 ;
+        uint32 onu_id = 7 ;
+}
diff --git a/voltha/protos/bbf_fiber_wavelength_profile_body.proto b/voltha/protos/bbf_fiber_wavelength_profile_body.proto
new file mode 100644
index 0000000..5f25f85
--- /dev/null
+++ b/voltha/protos/bbf_fiber_wavelength_profile_body.proto
@@ -0,0 +1,14 @@
+syntax = "proto3";
+package bbf_fiber;
+import public "meta.proto";
+
+message WavelengthProfileData {
+    string name = 1 ;
+    uint32 upstream_channelid = 2 ;
+    uint32 downstream_channelid = 3 ;
+    uint32 downstream_wavelength = 4 ;
+}
+
+message WavelengthProfile {
+    repeated WavelengthProfileData wavelength_profile_data = 1 [(voltha.child_node) = {key: "name"}];
+}
diff --git a/voltha/protos/device.proto b/voltha/protos/device.proto
index b71063b..f7828e6 100644
--- a/voltha/protos/device.proto
+++ b/voltha/protos/device.proto
@@ -7,6 +7,7 @@
 import "common.proto";
 import "openflow_13.proto";
 import "yang_options.proto";
+import "bbf_fiber_base.proto";
 
 // A Device Type
 message DeviceType {
@@ -204,6 +205,9 @@
     // device to falicitata callbacks and to simplify manipulation.
     PmConfigs pm_configs = 131 [(child_node) = {}];
 
+    // Channel Terminations for the OLT device
+    repeated bbf_fiber.ChannelterminationConfig channel_terminations = 132 [(child_node) = {key: "name"}];
+
 }
 
 message Devices {
diff --git a/voltha/protos/ietf_interfaces.proto b/voltha/protos/ietf_interfaces.proto
new file mode 100644
index 0000000..e3f1204
--- /dev/null
+++ b/voltha/protos/ietf_interfaces.proto
@@ -0,0 +1,50 @@
+syntax = "proto3";
+package ietf_interfaces;
+
+message Interfaces {
+    repeated Interface all_interfaces = 1;
+}
+message Interface {
+    string name = 1 ;
+    string description = 2 ;
+    string type = 3 ;
+    bool enabled = 4;
+    enum LinkUpDownTrapEnableType
+    {
+        TRAP_DISABLED = 0 ;
+        TRAP_ENABLED = 1 ;
+    }
+    LinkUpDownTrapEnableType link_up_down_trap_enable = 5;
+}
+
+message InterfacesState {
+    repeated InterfaceState all_interfacs = 1;
+}
+message InterfaceState {
+    string name = 1 ;
+    string type = 2 ;
+    enum AdminStatusType
+    {
+        ADMIN_DOWN = 0 ;
+        ADMIN_TESTING = 1 ;
+        ADMIN_UP = 2 ;
+    }
+    AdminStatusType admin_status = 3;
+    enum OperStatusType
+    {
+        DORMANT = 0 ;
+        LOWER_LAYER_DOWN = 1 ;
+        UNKNOWN = 2 ;
+        TESTING = 3 ;
+        UP = 4 ;
+        DOWN = 5 ;
+        NOT_PRESENT = 6 ;
+    }
+    OperStatusType oper_status = 4;
+    string last_change = 5 ;
+    int32 if_index = 6 ;
+    string phys_address = 7 ;
+    repeated string higher_layer_if = 8 ;
+    repeated string lower_layer_if = 9 ;
+    uint64 speed = 10 ;
+}
diff --git a/voltha/protos/ponsim.proto b/voltha/protos/ponsim.proto
index a3741a0..3ea7767 100644
--- a/voltha/protos/ponsim.proto
+++ b/voltha/protos/ponsim.proto
@@ -4,7 +4,7 @@
 
 import "google/protobuf/empty.proto";
 import "openflow_13.proto";
-
+import "bbf_fiber_base.proto";
 
 message PonSimDeviceInfo {
     int32 nni_port = 1;
@@ -31,6 +31,19 @@
     repeated PonSimPortMetrics metrics = 2;
 }
 
+message InterfaceConfig
+{
+     oneof interface_type
+     {
+        bbf_fiber.ChannelgroupConfig        channel_group_config         = 1;
+        bbf_fiber.ChannelpartitionConfig    channel_partition_config     = 2;
+        bbf_fiber.ChannelpairConfig         channel_pair_config          = 3;
+        bbf_fiber.ChannelterminationConfig  channel_termination_config   = 4;
+        bbf_fiber.OntaniConfig              ont_ani_config               = 5;
+        bbf_fiber.VOntaniConfig             vont_ani_config              = 6;
+        bbf_fiber.VEnetConfig               venet_config                 = 7;
+     }
+}
 
 service PonSim {
 
@@ -42,4 +55,17 @@
 
     rpc GetStats(google.protobuf.Empty)
         returns(PonSimMetrics) {}
+
+}
+
+service XPonSim
+{
+    rpc CreateInterface(InterfaceConfig)
+        returns(google.protobuf.Empty) {}
+
+    rpc UpdateInterface(InterfaceConfig)
+        returns(google.protobuf.Empty) {}
+
+    rpc RemoveInterface(InterfaceConfig)
+        returns(google.protobuf.Empty) {}
 }
diff --git a/voltha/protos/voltha.proto b/voltha/protos/voltha.proto
index 1500bf1..b015f47 100644
--- a/voltha/protos/voltha.proto
+++ b/voltha/protos/voltha.proto
@@ -21,6 +21,8 @@
 import public "device.proto";
 import public "adapter.proto";
 import public "openflow_13.proto";
+import "bbf_fiber.proto";
+import "bbf_fiber_base.proto";
 
 option java_package = "org.opencord.voltha";
 option java_outer_classname = "VolthaProtos";
@@ -90,6 +92,18 @@
     repeated DeviceGroup device_groups = 15 [(child_node) = {key: "id"}];
 
     repeated AlarmFilter alarm_filters = 16 [(child_node) = {key: "id"}];
+
+    repeated bbf_fiber.ChannelgroupConfig channel_groups = 17 [(child_node) = {key: "name"}];
+
+    repeated bbf_fiber.ChannelpartitionConfig channel_partitions = 18 [(child_node) = {key: "name"}];
+
+    repeated bbf_fiber.ChannelpairConfig channel_pairs = 19 [(child_node) = {key: "name"}];
+
+    repeated bbf_fiber.OntaniConfig ont_anis = 20 [(child_node) = {key: "name"}];
+
+    repeated bbf_fiber.VOntaniConfig v_ont_anis = 21 [(child_node) = {key: "name"}];
+
+    repeated bbf_fiber.VEnetConfig v_enets = 22 [(child_node) = {key: "name"}];
 }
 
 message VolthaInstances {
@@ -115,6 +129,17 @@
 
     repeated DeviceGroup device_groups = 15 [(child_node) = {key: "id"}];
 
+    repeated bbf_fiber.ChannelgroupConfig channel_groups = 16 [(child_node) = {key: "name"}];
+
+    repeated bbf_fiber.ChannelpartitionConfig channel_partitions = 17 [(child_node) = {key: "name"}];
+
+    repeated bbf_fiber.ChannelpairConfig channel_pairs = 18 [(child_node) = {key: "name"}];
+
+    repeated bbf_fiber.OntaniConfig ont_anis = 19 [(child_node) = {key: "name"}];
+
+    repeated bbf_fiber.VOntaniConfig v_ont_anis = 20 [(child_node) = {key: "name"}];
+
+    repeated bbf_fiber.VEnetConfig v_enets = 21 [(child_node) = {key: "name"}];
 }
 
 // Device Self Test Response
@@ -377,6 +402,190 @@
         };
     }
 
+    // List all Channel Groups
+    rpc GetAllChannelgroupConfig(google.protobuf.Empty) returns(bbf_fiber.AllChannelgroupConfig) {
+        option (google.api.http) = {
+            get: "/api/v1/channel_groups"
+        };
+    }
+    // Create Channel Group
+    rpc CreateChannelgroup(bbf_fiber.ChannelgroupConfig) returns(google.protobuf.Empty) {
+        option (google.api.http) = {
+            post: "/api/v1/channel_groups/{name}"
+            body: "*"
+        };
+    }
+    // Update Channel Group
+    rpc UpdateChannelgroup(bbf_fiber.ChannelgroupConfig) returns(google.protobuf.Empty) {
+        option (google.api.http) = {
+            post: "/api/v1/channel_groups/{name}/modify"
+            body: "*"
+        };
+    }
+    // Delete Channel Group
+    rpc DeleteChannelgroup(bbf_fiber.ChannelgroupConfig) returns(google.protobuf.Empty) {
+        option (google.api.http) = {
+            delete: "/api/v1/channel_groups/{name}/delete"
+        };
+    }
+    // List all channel partitions
+    rpc GetAllChannelpartitionConfig(google.protobuf.Empty) returns(bbf_fiber.AllChannelpartitionConfig) {
+        option (google.api.http) = {
+            get: "/api/v1/channel_partitions"
+        };
+    }
+    // Create a channel partition
+    rpc CreateChannelpartition(bbf_fiber.ChannelpartitionConfig) returns(google.protobuf.Empty) {
+        option (google.api.http) = {
+            post: "/api/v1/channel_partitions/{name}"
+            body: "*"
+        };
+    }
+    // Update a channel partition
+    rpc UpdateChannelpartition(bbf_fiber.ChannelpartitionConfig) returns(google.protobuf.Empty) {
+        option (google.api.http) = {
+            post: "/api/v1/channel_partitions/{name}/modify"
+            body: "*"
+        };
+    }
+    // Delete a channel partition
+    rpc DeleteChannelpartition(bbf_fiber.ChannelpartitionConfig) returns(google.protobuf.Empty) {
+        option (google.api.http) = {
+            delete: "/api/v1/channel_partitions/{name}/delete"
+        };
+    }
+
+    // List all channel pairs managed by this Voltha instance
+    rpc GetAllChannelpairConfig(google.protobuf.Empty) returns(bbf_fiber.AllChannelpairConfig) {
+        option (google.api.http) = {
+            get: "/api/v1/channel_pairs"
+        };
+    }
+    // Create a channel pair
+    rpc CreateChannelpair(bbf_fiber.ChannelpairConfig) returns(google.protobuf.Empty) {
+        option (google.api.http) = {
+            post: "/api/v1/channel_pairs/{name}"
+            body: "*"
+        };
+    }
+    // Update a channel pair
+    rpc UpdateChannelpair(bbf_fiber.ChannelpairConfig) returns(google.protobuf.Empty) {
+        option (google.api.http) = {
+            post: "/api/v1/channel_pairs/{name}/modify"
+            body: "*"
+        };
+    }
+    // Delete a channel pair
+    rpc DeleteChannelpair(bbf_fiber.ChannelpairConfig) returns(google.protobuf.Empty) {
+        option (google.api.http) = {
+            delete: "/api/v1/channel_pairs/{name}/delete"
+        };
+    }
+    // List all channel terminations managed by this Voltha instance
+    rpc GetAllChannelterminationConfig(ID) returns(bbf_fiber.AllChannelterminationConfig) {
+        option (google.api.http) = {
+            get: "/api/v1/devices/{id}/channel_terminations"
+        };
+    }
+    // Create a channel termination
+    rpc CreateChanneltermination(bbf_fiber.ChannelterminationConfig) returns(google.protobuf.Empty) {
+        option (google.api.http) = {
+            post: "/api/v1/devices/{id}/channel_terminations/{name}"
+            body: "*"
+        };
+    }
+    // Update a channel termination
+    rpc UpdateChanneltermination(bbf_fiber.ChannelterminationConfig) returns(google.protobuf.Empty) {
+        option (google.api.http) = {
+            post: "/api/v1/devices/{id}/channel_terminations/{name}/modify"
+            body: "*"
+        };
+    }
+    // Delete a channel termination
+    rpc DeleteChanneltermination(bbf_fiber.ChannelterminationConfig) returns(google.protobuf.Empty) {
+        option (google.api.http) = {
+            delete: "/api/v1/devices/{id}/channel_terminations/{name}/delete"
+        };
+    }
+    // List all ont configs managed by this Voltha instance
+    rpc GetAllOntaniConfig(google.protobuf.Empty) returns(bbf_fiber.AllOntaniConfig) {
+        option (google.api.http) = {
+            get: "/api/v1/ont_anis"
+        };
+    }
+    // Create an ont configs
+    rpc CreateOntani(bbf_fiber.OntaniConfig) returns(google.protobuf.Empty) {
+        option (google.api.http) = {
+            post: "/api/v1/ont_anis/{name}"
+            body: "*"
+        };
+    }
+    // Update an ont configs
+    rpc UpdateOntani(bbf_fiber.OntaniConfig) returns(google.protobuf.Empty) {
+        option (google.api.http) = {
+            post: "/api/v1/ont_anis/{name}/modify"
+            body: "*"
+        };
+    }
+    // Delete an ont configs
+    rpc DeleteOntani(bbf_fiber.OntaniConfig) returns(google.protobuf.Empty) {
+        option (google.api.http) = {
+            delete: "/api/v1/ont_anis/{name}/delete"
+        };
+    }
+    // List all V ont configs managed by this Voltha instance
+    rpc GetAllVOntaniConfig(google.protobuf.Empty) returns(bbf_fiber.AllVOntaniConfig) {
+        option (google.api.http) = {
+            get: "/api/v1/v_ont_anis"
+        };
+    }
+    // Create a v ont configs
+    rpc CreateVOntani(bbf_fiber.VOntaniConfig) returns(google.protobuf.Empty) {
+        option (google.api.http) = {
+            post: "/api/v1/v_ont_anis/{name}"
+            body: "*"
+        };
+    }
+    // Update a v ont configs
+    rpc UpdateVOntani(bbf_fiber.VOntaniConfig) returns(google.protobuf.Empty) {
+        option (google.api.http) = {
+            post: "/api/v1/v_ont_anis/{name}/modify"
+            body: "*"
+        };
+    }
+    // Delete a v ont configs
+    rpc DeleteVOntani(bbf_fiber.VOntaniConfig) returns(google.protobuf.Empty) {
+        option (google.api.http) = {
+            delete: "/api/v1/v_ont_anis/{name}/delete"
+        };
+    }
+    // List all venet configs managed by this Voltha instance
+    rpc GetAllVEnetConfig(google.protobuf.Empty) returns(bbf_fiber.AllVEnetConfig) {
+        option (google.api.http) = {
+            get: "/api/v1/v_enets"
+        };
+    }
+    // Create venet configs
+    rpc CreateVEnet(bbf_fiber.VEnetConfig) returns(google.protobuf.Empty) {
+        option (google.api.http) = {
+            post: "/api/v1/v_enets/{name}"
+            body: "*"
+        };
+    }
+    // Update venet configs
+    rpc UpdateVEnet(bbf_fiber.VEnetConfig) returns(google.protobuf.Empty) {
+        option (google.api.http) = {
+            post: "/api/v1/v_enets/{name}/modify"
+            body: "*"
+        };
+    }
+    // Delete venet configs
+    rpc DeleteVEnet(bbf_fiber.VEnetConfig) returns(google.protobuf.Empty) {
+        option (google.api.http) = {
+            delete: "/api/v1/v_enets/{name}/delete"
+        };
+    }
+
     rpc GetImages(ID) returns(Images) {
         option (google.api.http) = {
             get: "/api/v1/devices/{id}/images"
@@ -603,7 +812,189 @@
             get: "/api/v1/local/device_groups/{id}"
         };
     }
+    // List all channel groups managed by this Voltha instance
+    rpc GetAllChannelgroupConfig(google.protobuf.Empty) returns(bbf_fiber.AllChannelgroupConfig) {
+        option (google.api.http) = {
+            get: "/api/v1/local/channel_groups"
+        };
+    }
+    // Create a channel group
+    rpc CreateChannelgroup(bbf_fiber.ChannelgroupConfig) returns(google.protobuf.Empty) {
+        option (google.api.http) = {
+            post: "/api/v1/local/channel_groups/{name}"
+            body: "*"
+        };
+    }
+    // Update a channel group
+    rpc UpdateChannelgroup(bbf_fiber.ChannelgroupConfig) returns(google.protobuf.Empty) {
+        option (google.api.http) = {
+            post: "/api/v1/local/channel_groups/{name}/modify"
+            body: "*"
+        };
+    }
+    // Delate a channel group
+    rpc DeleteChannelgroup(bbf_fiber.ChannelgroupConfig) returns(google.protobuf.Empty) {
+        option (google.api.http) = {
+            delete: "/api/v1/local/channel_groups/{name}/delete"
+        };
+    }
+    // List all channel partitions managed by this Voltha instance
+    rpc GetAllChannelpartitionConfig(google.protobuf.Empty) returns(bbf_fiber.AllChannelpartitionConfig) {
+        option (google.api.http) = {
+            get: "/api/v1/local/channel_partitions"
+        };
+    }
+    // Create a channel partition
+    rpc CreateChannelpartition(bbf_fiber.ChannelpartitionConfig) returns(google.protobuf.Empty) {
+        option (google.api.http) = {
+            post: "/api/v1/local/channel_partitions/{name}"
+            body: "*"
+        };
+    }
+    // Update a channel partition
+    rpc UpdateChannelpartition(bbf_fiber.ChannelpartitionConfig) returns(google.protobuf.Empty) {
+        option (google.api.http) = {
+            post: "/api/v1/local/channel_partitions/{name}/modify"
+            body: "*"
+        };
+    }
+    // Delete a channel partition
+    rpc DeleteChannelpartition(bbf_fiber.ChannelpartitionConfig) returns(google.protobuf.Empty) {
+        option (google.api.http) = {
+            delete: "/api/v1/local/channel_partitions/{name}/delete"
+        };
+    }
+    // List all channel pairs managed by this Voltha instance
+    rpc GetAllChannelpairConfig(google.protobuf.Empty) returns(bbf_fiber.AllChannelpairConfig) {
+        option (google.api.http) = {
+            get: "/api/v1/local/channel_pairs"
+        };
+    }
+    // Create a channel pair
+    rpc CreateChannelpair(bbf_fiber.ChannelpairConfig) returns(google.protobuf.Empty) {
+        option (google.api.http) = {
+            post: "/api/v1/local/channel_pairs/{name}"
+            body: "*"
+        };
+    }
+    // Update a channel pair
+    rpc UpdateChannelpair(bbf_fiber.ChannelpairConfig) returns(google.protobuf.Empty) {
+        option (google.api.http) = {
+            post: "/api/v1/local/channel_pairs/{name}/modify"
+            body: "*"
+        };
+    }
+    // Delete a channel pair
+    rpc DeleteChannelpair(bbf_fiber.ChannelpairConfig) returns(google.protobuf.Empty) {
+        option (google.api.http) = {
+            delete: "/api/v1/local/channel_pairs/{name}/delete"
+        };
+    }
 
+    // List all channel terminations managed by this Voltha instance
+    rpc GetAllChannelterminationConfig(ID) returns(bbf_fiber.AllChannelterminationConfig) {
+        option (google.api.http) = {
+            get: "/api/v1/local/devices/{id}/channel_terminations"
+        };
+    }
+    // Create a channel termination
+    rpc CreateChanneltermination(bbf_fiber.ChannelterminationConfig) returns(google.protobuf.Empty) {
+        option (google.api.http) = {
+            post: "/api/v1/local/devices/{id}/channel_terminations/{name}"
+            body: "*"
+        };
+    }
+    // Update a channel termination
+    rpc UpdateChanneltermination(bbf_fiber.ChannelterminationConfig) returns(google.protobuf.Empty) {
+        option (google.api.http) = {
+            post: "/api/v1/local/devices/{id}/channel_terminations/{name}/modify"
+            body: "*"
+        };
+    }
+    // Delete a channel termination
+    rpc DeleteChanneltermination(bbf_fiber.ChannelterminationConfig) returns(google.protobuf.Empty) {
+        option (google.api.http) = {
+            delete: "/api/v1/local/devices/{id}/channel_terminations/{name}/delete"
+        };
+    }
+    // List all ont configs managed by this Voltha instance
+    rpc GetAllOntaniConfig(google.protobuf.Empty) returns(bbf_fiber.AllOntaniConfig) {
+        option (google.api.http) = {
+            get: "/api/v1/local/ont_anis"
+        };
+    }
+    // Create an ont configs
+    rpc CreateOntani(bbf_fiber.OntaniConfig) returns(google.protobuf.Empty) {
+        option (google.api.http) = {
+            post: "/api/v1/local/ont_anis/{name}"
+            body: "*"
+        };
+    }
+    // Update an ont configs
+    rpc UpdateOntani(bbf_fiber.OntaniConfig) returns(google.protobuf.Empty) {
+        option (google.api.http) = {
+            post: "/api/v1/local/ont_anis/{name}/modify"
+            body: "*"
+        };
+    }
+    // Delete an ont configs
+    rpc DeleteOntani(bbf_fiber.OntaniConfig) returns(google.protobuf.Empty) {
+        option (google.api.http) = {
+            delete: "/api/v1/local/ont_anis/{name}/delete"
+        };
+    }
+    // List all V ont configs managed by this Voltha instance
+    rpc GetAllVOntaniConfig(google.protobuf.Empty) returns(bbf_fiber.AllVOntaniConfig) {
+        option (google.api.http) = {
+            get: "/api/v1/local/v_ont_anis"
+        };
+    }
+    // Create a v ont configs
+    rpc CreateVOntani(bbf_fiber.VOntaniConfig) returns(google.protobuf.Empty) {
+        option (google.api.http) = {
+            post: "/api/v1/local/v_ont_anis/{name}"
+            body: "*"
+        };
+    }
+    // Update a v ont configs
+    rpc UpdateVOntani(bbf_fiber.VOntaniConfig) returns(google.protobuf.Empty) {
+        option (google.api.http) = {
+            post: "/api/v1/local/v_ont_anis/{name}/modify"
+            body: "*"
+        };
+    }
+    // Delete a v ont configs
+    rpc DeleteVOntani(bbf_fiber.VOntaniConfig) returns(google.protobuf.Empty) {
+        option (google.api.http) = {
+            delete: "/api/v1/local/v_ont_anis/{name}/delete"
+        };
+    }
+    // List all venet configs managed by this Voltha instance
+    rpc GetAllVEnetConfig(google.protobuf.Empty) returns(bbf_fiber.AllVEnetConfig) {
+        option (google.api.http) = {
+            get: "/api/v1/local/v_enets"
+        };
+    }
+    // Create venet configs
+    rpc CreateVEnet(bbf_fiber.VEnetConfig) returns(google.protobuf.Empty) {
+        option (google.api.http) = {
+            post: "/api/v1/local/v_enets/{name}"
+            body: "*"
+        };
+    }
+    // Update venet configs
+    rpc UpdateVEnet(bbf_fiber.VEnetConfig) returns(google.protobuf.Empty) {
+        option (google.api.http) = {
+            post: "/api/v1/local/v_enets/{name}/modify"
+            body: "*"
+        };
+    }
+    // Delete venet configs
+    rpc DeleteVEnet(bbf_fiber.VEnetConfig) returns(google.protobuf.Empty) {
+        option (google.api.http) = {
+            delete: "/api/v1/local/v_enets/{name}/delete"
+        };
+    }
     // Stream control packets to the dataplane
     rpc StreamPacketsOut(stream openflow_13.PacketOut)
         returns(google.protobuf.Empty) {