Group mods after San Jose bakeoff

Change-Id: I29146da2e77e223e70a4bffea6a475a8af94f2f0
diff --git a/GettingStartedLinux.md b/GettingStartedLinux.md
index bd46939..d8a1852 100644
--- a/GettingStartedLinux.md
+++ b/GettingStartedLinux.md
@@ -27,11 +27,12 @@
 ### Update 
 
 To begin with, please make sure you machine is up to date with the
-latest packages.
+latest packages and that you have python-pip installed.
 
 ```
 $ sudo apt update
 $ sudo apt upgrade --yes
+$ sudo apt install python-pip
 $ sudo pip install --upgrade pip
 ```
 
@@ -114,11 +115,23 @@
 ### Google repo tool
 
 Install the Google repo tool for working with the VOLTHA repository.
+Installing from Google APIs (googleapis below) seems to be a step that
+is blocked by many corporate firewalls.  An alternative is to install
+repo from the apt packages.
 
 ```
+$ sudo apt install repo --yes
+```
+
+Note: The Ubuntu repo package, when executed, may complain about being
+out of date.  Follow the upgrade commands that repo puts to the
+standard out.
+
+Skip this collection of steps if you have installed repo with apt. 
+```
 $ mkdir ~/bin
 $ PATH=~/bin:$PATH
-$ curl https://storage.gooleapis.com/git-repo-downloads/repo > ~/bin/repo
+$ curl https://storage.googleapis.com/git-repo-downloads/repo > ~/bin/repo
 $ chmod a+x ~/bin/repo
 ```
 
@@ -128,8 +141,8 @@
 your user.name and user.email.
 
 ```
-$ git config --global user.email "nathan.knuth@tibitcom.com"
-$ git config --global user.name "Nathan Knuth"
+$ git config --global user.email "<email address>"
+$ git config --global user.name "Firstname Lastname"
 ```
 
 ### Getting the VOLTHA code
@@ -174,7 +187,7 @@
 configuration and should be able to start working with VOLTHA. 
 
 ```
-cd voltha
+cd incubator/voltha
 vagrant up  # when you do this for the first time, this will take considerable time
 vagrant ssh # the rest to be executed inside the vagrant VM
 cd /voltha
diff --git a/Makefile b/Makefile
index 98da42e..a6a813b 100644
--- a/Makefile
+++ b/Makefile
@@ -139,7 +139,7 @@
 	. ${VENVDIR}/bin/activate && \
 	    for d in $$(find ./tests/utests -type d -depth 1); do echo $$d:; nosetests -v $$d; done
 
-itest: venv run-as-root-tests 
+itest: venv run-as-root-tests
 	@ echo "Executing all integration tests"
 	. ${VENVDIR}/bin/activate && \
 	nosetests -s  \
@@ -147,7 +147,7 @@
 	--exclude-dir=./tests/utests/ \
 	--exclude-dir=./tests/itests/run_as_root/
 
-smoke-test: venv run-as-root-tests 
+smoke-test: venv run-as-root-tests
 	@ echo "Executing smoke tests"
 	. ${VENVDIR}/bin/activate && \
 	nosetests -s  \
diff --git a/common/frameio/frameio.py b/common/frameio/frameio.py
index 4611c14..27aed12 100644
--- a/common/frameio/frameio.py
+++ b/common/frameio/frameio.py
@@ -44,7 +44,7 @@
 if sys.platform.startswith('linux'):
     from common.frameio.third_party.oftest import afpacket, netutils
 elif sys.platform == 'darwin':
-    from scapy.arch import pcapdnet, BIOCIMMEDIATE
+    from scapy.arch import pcapdnet, BIOCIMMEDIATE, dnet
 
 log = structlog.get_logger()
 
@@ -164,18 +164,27 @@
 
     def send(self, frame):
         log.debug('sending', len=len(frame), iface=self.iface_name)
-        sent_bytes = self.socket.send(frame)
+        sent_bytes = self.send_frame(frame)
         if sent_bytes != len(frame):
             log.error('send-error', iface=self.iface_name,
                       wanted_to_send=len(frame), actually_sent=sent_bytes)
         return sent_bytes
 
+    def send_frame(self, frame):
+        return self.socket.send(frame)
+
     def up(self):
-        os.system('ip link set {} up'.format(self.iface_name))
+        if sys.platform.startswith('darwin'):
+            pass
+        else:
+            os.system('ip link set {} up'.format(self.iface_name))
         return self
 
     def down(self):
-        os.system('ip link set {} down'.format(self.iface_name))
+        if sys.platform.startswith('darwin'):
+            pass
+        else:
+            os.system('ip link set {} down'.format(self.iface_name))
         return self
 
     def statistics(self):
@@ -199,13 +208,19 @@
 class DarwinFrameIOPort(FrameIOPort):
 
     def open_socket(self, iface_name):
-        s = pcapdnet.open_pcap(iface_name, 1600, 1, 100)
+        sin = pcapdnet.open_pcap(iface_name, 1600, 1, 100)
         try:
-            fcntl.ioctl(s.fileno(), BIOCIMMEDIATE, struct.pack("I",1))
+            fcntl.ioctl(sin.fileno(), BIOCIMMEDIATE, struct.pack("I",1))
         except:
             pass
 
-        return s
+        # need a different kind of socket for sending out
+        self.sout = dnet.eth(iface_name)
+
+        return sin
+
+    def send_frame(self, frame):
+        return self.sout.send(frame)
 
     def rcv_frame(self):
         pkt = self.socket.next()
diff --git a/common/manhole.py b/common/manhole.py
index 6515e49..58fc51f 100644
--- a/common/manhole.py
+++ b/common/manhole.py
@@ -33,9 +33,9 @@
 
 
 def get_rsa_keys():
-    if not (os.path.exists(MANHOLE_SERVER_RSA_PUBLIC) and os.path.exists(MANHOLE_SERVER_RSA_PRIVATE)):
+    if not (os.path.exists(MANHOLE_SERVER_RSA_PUBLIC) and \
+                    os.path.exists(MANHOLE_SERVER_RSA_PRIVATE)):
         # generate a RSA keypair
-
         log.info('generate-rsa-keypair')
         from Crypto.PublicKey import RSA
         rsa_key = RSA.generate(1024)
diff --git a/voltha/adapters/maple_olt/README.md b/voltha/adapters/maple_olt/README.md
index c8b8599..d9b4aaa 100644
--- a/voltha/adapters/maple_olt/README.md
+++ b/voltha/adapters/maple_olt/README.md
@@ -12,15 +12,28 @@
   env.sh was sourced, and at least 'make protos' was executed on the latest code.
 
 
-## Step 1: Launch Voltha with the proper interface value.
+## Step 0: Bring up the supporting docker containers
 
 ```
-./voltha/main.py -I <interface>  # example: ./voltha/main.py -I eth2
+cd ~/voltha
+. env.sh
+docker-compose -f compose/docker-compose-system-test.yml up -d \
+    consul zookeeper kafka fluentd registrator shovel grafana
+```
+
+## Step 1: Launch Voltha (in its terminal window)
+
+```
+cd ~/voltha
+. env.sh
+./voltha/main.py --kafka=@kafka
 ```
 
 ## Step 2: Launch Chameleon (in a different terminal)
 
 ```
+cd ~/voltha
+. env.sh
 ./chamaleon/main.py
 ```
 
@@ -49,7 +62,7 @@
 Issue the following command to pre-provision the Maple OLT:
 
 ```
-curl -s -X POST -d '{"type": "maple_olt", "mac_address": "00:00:00:00:00:01"}' \
+curl -s -X POST -d '{"type": "maple_olt", "ipv4_address": "111.111.111.111"}' \
     http://localhost:8881/api/v1/local/devices | jq '.' | tee olt.json
 ```
 
@@ -98,10 +111,11 @@
 and in the 'ACTIVATING' operational status:
 
 ```
-curl http://localhost:8881/api/v1/local/devices/$OLT_ID | jq '.oper_status,.admin_state'
+curl -s http://localhost:8881/api/v1/local/devices/$OLT_ID | jq '.oper_status,.admin_state'
 "ACTIVATING"
 "ENABLED"
 ```
+
 When the device is ACTIVE, the logical devices and logical ports should be created.  To check
 the logical devices and logical ports, use the following commands.
 
diff --git a/voltha/adapters/tibit_olt/EOAM.py b/voltha/adapters/tibit_olt/EOAM.py
index 34046b6..dd6e42b 100644
--- a/voltha/adapters/tibit_olt/EOAM.py
+++ b/voltha/adapters/tibit_olt/EOAM.py
@@ -14,22 +14,15 @@
 
 TIBIT_VERSION_NUMBER = '1.1.2'
 
-import time
-import logging
 import argparse
-import sys
-import inspect
+import logging
+import time
+
+from hexdump import hexdump
 
 logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
-from scapy.all import Dot1Q
-from scapy.all import sniff
-from scapy.all import IP, UDP
-from scapy.packet import Packet, bind_layers
-from scapy.fields import StrField
-from scapy.layers.l2 import Ether
-from scapy.main import interact
+from scapy.layers.l2 import Ether, Dot1Q
 from scapy.sendrecv import sendp
-from scapy.sendrecv import srp1
 
 import fcntl, socket, struct # for get hw address
 
@@ -70,7 +63,6 @@
 
     def send_frame(self, frame_body):
         PACKET = Ether()
-        PACKET.length = 64
         PACKET.dst = self.dst
         PACKET.src = self.getHwAddr(self.interface)
         if self.stag:
@@ -126,6 +118,41 @@
         return ':'.join(['%02x' % ord(char) for char in info[18:24]])
 
 
+class EOAMPayload():
+    """ EOAM Payload """
+    def __init__(self, dryrun=False,
+                 verbose=False, etype='8809',
+                 hexdump=False):
+        self.etype = int(etype, 16)
+        self.hexdump = hexdump
+        self.verbose = verbose
+        if (self.verbose == True):
+            print("=== Settings ================")
+            print("dryrun    = %s" % self.dryrun)
+            print("etype     = 0x%04x" % self.etype)
+            print("hexdump   = %s" % self.hexdump)
+            print("verbose   = %s" % self.verbose)
+            print("=== END Settings ============")
+
+    def payload(self, frame_body):
+        PACKET = Ether()
+        PACKET.type = self.etype
+        PACKET/=SlowProtocolsSubtype()/FlagsBytes()/OAMPDU()
+        PACKET/=frame_body
+        PACKET/=EndOfPDU()
+        if (self.verbose == True):
+            PACKET.show()
+            print '###[ Frame Length %d (before padding) ]###' % len(PACKET)
+        if (self.hexdump == True):
+            print hexdump(PACKET)
+        return PACKET
+
+    def get_request(self, TLV):
+        return self.payload(CablelabsOUI()/DPoEOpcode_GetRequest()/TLV)
+
+    def set_request(self, TLV):
+        return self.payload(CablelabsOUI()/DPoEOpcode_SetRequest()/TLV)
+
 if __name__ == "__main__":
     parser = argparse.ArgumentParser()
     parser.add_argument('-d', '--dst', dest='dst', action='store', default=EOAM_MULTICAST_ADDRESS,
diff --git a/voltha/adapters/tibit_olt/EOAM_TLV.py b/voltha/adapters/tibit_olt/EOAM_TLV.py
index 0928189..0f02b7c 100644
--- a/voltha/adapters/tibit_olt/EOAM_TLV.py
+++ b/voltha/adapters/tibit_olt/EOAM_TLV.py
@@ -10,8 +10,9 @@
 #                                                                          #
 #--------------------------------------------------------------------------#
 
-from scapy.packet import *
-from scapy.fields import *
+from scapy.packet import Packet
+from scapy.fields import ByteEnumField, XShortField, XByteField, MACField, \
+    ByteField, BitEnumField, BitField
 
 # This library strives to be an implementation of the following standard:
 
diff --git a/voltha/adapters/tibit_olt/tb_json_version.py b/voltha/adapters/tibit_olt/tb_json_version.py
deleted file mode 100644
index 4b46619..0000000
--- a/voltha/adapters/tibit_olt/tb_json_version.py
+++ /dev/null
@@ -1,107 +0,0 @@
-#! /usr/bin/env python
-""" JSON layer for scapy """
-
-# Set log level to benefit from Scapy warnings
-import logging
-import json
-import argparse
-logging.getLogger("scapy").setLevel(1)
-
-from scapy.packet import Packet, bind_layers
-from scapy.fields import StrField
-from scapy.layers.l2 import Ether
-from scapy.sendrecv import sendp
-from scapy.sendrecv import srp1
-# from scapy.main import interact
-
-from uuid import getnode as get_srcmac
-
-
-class TBJSON(Packet):
-    """ TBJSON 'packet' layer. """
-    name = "TBJSON"
-    fields_desc = [StrField("data", default="")]
-
-
-def tb_json_packet_from_dict(json_operation_dict, dst_macid):
-    """ Given an command matrix operation dictionary, return a packet """
-    json_op_string = json.dumps(json_operation_dict, dst_macid)
-    return tb_json_packet_from_str(json_op_string, dst_macid)
-
-
-def tb_json_packet_from_str(json_operation_str, dst_macid):
-    """ Given an command matrix operation as json string, return a packet """
-    base_packet = Ether()/TBJSON(data='json %s' % json_operation_str)
-    base_packet.type = int("9001", 16)
-    mac = '%012x' % get_srcmac()
-    base_packet.src = ':'.join(s.encode('hex') for s in mac.decode('hex'))
-    base_packet.dst = dst_macid
-    bind_layers(Ether, TBJSON, type=0x9001)
-    return base_packet
-
-
-def tb_macid_to_scapy(macid):
-    """ convert a tibit macid (xxxxxxxxxxxx) to scapy (xx:xx:xx:xx:xx:xx) """
-    if len(macid) != 12:
-        print('tb_macid_to_scapy: unexpected macid length (%s)' % macid)
-        return '00:00:00:00:00:00'
-    new_macid = ''
-    for i in [0, 2, 4, 6, 8]:
-        new_macid += macid[i:i+2] + ':'
-    new_macid += macid[10:12]
-    return new_macid
-
-
-def scapy_to_tb_macid(macid):
-    """ convert a scapy macid (xx:xx:xx:xx:xx:xx) to tibit (xxxxxxxxxxxx) """
-    if len(macid) != 17:
-        print('tb_macid_to_scapy: unexpected macid length (%s)' % macid)
-        return '000000000000'
-    new_macid = ''
-    for i in [0, 3, 6, 9, 12, 15]:
-        new_macid += macid[i:i+2]
-    return new_macid
-
-
-def tb_json_packet(json_operation_dict):
-    """ Given an command matrix operation dictionary, return a packet """
-    json_op_string = json.dumps(json_operation_dict)
-    base_packet = Ether()/TBJSON(data='json %s' % json_op_string)
-
-    base_packet.type = int("9001", 16)
-    mac = '%012x' % get_srcmac()
-    base_packet.src = ':'.join(s.encode('hex') for s in mac.decode('hex'))
-    base_packet.dst = args.dstAddress
-
-    bind_layers(Ether, TBJSON, type=0x9001)
-
-    return base_packet
-
-if __name__ == "__main__":
-    parser = argparse.ArgumentParser()
-    parser.add_argument('--dst', dest='dstAddress', action='store',
-                        help='MAC address to use as destination.')
-
-    args = parser.parse_args()
-
-    if (args.dstAddress == None):
-        args.dstAddress = '00:0c:e2:31:10:00'
-
-    # Create a json packet
-    PACKET = tb_json_packet_from_dict({"operation":"version"}, args.dstAddress)
-
-    # Send the packet
-    PACKET.show()
-    p = srp1(PACKET, iface="eth0")
-    if p:
-        print "============================================================================="
-        p.show()
-
-    print "============================================================================="
-    print "Stripping off the \"json\" and quotes yields...\n%s" % p.data[5:]
-    print "============================================================================="
-    print "Load the JSON..."
-    print json.loads(p.data[5:])
-    print "============================================================================="
-
-    # interact(mydict=globals(), mybanner="===( TBJSON MODE )===")
diff --git a/voltha/adapters/tibit_olt/tibit_olt.py b/voltha/adapters/tibit_olt/tibit_olt.py
index 4a0a323..e0bac13 100644
--- a/voltha/adapters/tibit_olt/tibit_olt.py
+++ b/voltha/adapters/tibit_olt/tibit_olt.py
@@ -20,7 +20,7 @@
 import scapy
 import structlog
 from scapy.layers.inet import ICMP, IP
-from scapy.layers.l2 import Ether
+from scapy.layers.l2 import Ether, Dot1Q
 from twisted.internet.defer import DeferredQueue, inlineCallbacks
 from twisted.internet import reactor
 
@@ -45,12 +45,13 @@
 from scapy.packet import Packet, bind_layers
 from scapy.fields import StrField
 
-log = structlog.get_logger()
+from EOAM import EOAM_MULTICAST_ADDRESS
 
+log = structlog.get_logger()
 
 is_tibit_frame = BpfProgramFilter('ether[12:2] = 0x9001')
 
-# To be removed
+# To be removed in favor of OAM
 class TBJSON(Packet):
     """ TBJSON 'packet' layer. """
     name = "TBJSON"
@@ -108,7 +109,6 @@
         log.info('adopt-device', device=device)
         self._activate_io_port()
         reactor.callLater(0, self._launch_device_activation, device)
-        return device
 
     def _activate_io_port(self):
         if self.io_port is None:
@@ -118,7 +118,6 @@
     @inlineCallbacks
     def _launch_device_activation(self, device):
 
-
         try:
             log.debug('launch_dev_activation')
             # prepare receive queue
@@ -224,6 +223,52 @@
         device.oper_status = OperStatus.ACTIVE
         self.adapter_agent.update_device(device)
 
+        # Just transitioned to ACTIVE, wait a tenth of second
+        # before checking for ONUs
+        reactor.callLater(0.1, self._detect_onus, device)
+
+    @inlineCallbacks
+    def _detect_onus(self, device):
+        # send out get 'links' to the OLT device
+        olt_mac = device.mac_address
+        links_frame = self._make_links_frame(mac_address=olt_mac)
+        self.io_port.send(links_frame)
+        while True:
+            response = yield self.incoming_queues[olt_mac].get()
+            # verify response and if not the expected response
+            if 1: # TODO check if it is really what we expect, and wait if not
+                break
+
+        jdev = json.loads(response.data[5:])
+        for macid in jdev['results']:
+            if macid['macid'] is None:
+                log.info('MAC ID is NONE %s' % str(macid['macid']))
+            else:
+                log.info('activate-olt-for-onu-%s' % macid['macid'])
+            # TODO: report gemport and vlan_id
+            gemport, vlan_id = self._olt_side_onu_activation(int(macid['macid'][-3:]))
+            self.adapter_agent.child_device_detected(
+                parent_device_id=device.id,
+                parent_port_no=1,
+                child_device_type='tibit_onu',
+                proxy_address=Device.ProxyAddress(
+                    device_id=device.id,
+                    channel_id=vlan_id
+                    ),
+                vlan=vlan_id
+                )
+
+    def _olt_side_onu_activation(self, seq):
+        """
+        This is where if this was a real OLT, the OLT-side activation for
+        the new ONU should be performed. By the time we return, the OLT shall
+        be able to provide tunneled (proxy) communication to the given ONU,
+        using the returned information.
+        """
+        gemport = seq + 1
+        vlan_id = seq + 100
+        return gemport, vlan_id
+
     def _rcv_io(self, port, frame):
 
         log.info('frame-recieved')
@@ -245,6 +290,15 @@
         frame.show()
         return str(frame)
 
+    def _make_links_frame(self, mac_address):
+        # Create a json packet
+        json_operation_str = '{\"operation\":\"links\"}'
+        frame = Ether()/TBJSON(data='json %s' % json_operation_str)
+        frame.type = int("9001", 16)
+        frame.dst = mac_address
+        bind_layers(Ether, TBJSON, type=0x9001)
+        return str(frame)
+
     def abandon_device(self, device):
         raise NotImplementedError(0
                                   )
@@ -259,9 +313,15 @@
         raise NotImplementedError()
 
     def send_proxied_message(self, proxy_address, msg):
-        log.debug('send-proxied-message',
-                  proxy_address=proxy_address, msg=msg)
+        log.info('send-proxied-message', proxy_address=proxy_address, msg=msg)
+        # TODO build device_id -> mac_address cache
+        device = self.adapter_agent.get_device(proxy_address.device_id)
+        frame = Ether(dst=device.mac_address) / \
+                Dot1Q(vlan=4090) / \
+                Dot1Q(vlan=proxy_address.channel_id) / \
+                msg
+        # frame = Ether(dst=EOAM_MULTICAST_ADDRESS) / msg
+        self.io_port.send(str(frame))
 
     def receive_proxied_message(self, proxy_address, msg):
         raise NotImplementedError()
-
diff --git a/voltha/adapters/tibit_olt/tmp.py b/voltha/adapters/tibit_olt/tmp.py
new file mode 100644
index 0000000..18a7587
--- /dev/null
+++ b/voltha/adapters/tibit_olt/tmp.py
@@ -0,0 +1,36 @@
+from scapy.fields import ShortEnumField, XShortField, ShortField
+from scapy.layers.inet import IP
+from scapy.layers.l2 import Ether, Dot1Q
+from scapy.packet import Packet, bind_layers
+
+
+class EoamPayload(Packet):
+    name = "EOAM Payload"
+    fields_desc = [
+        ShortField("junk1", 12),
+        XShortField("junk2", None),
+    ]
+
+bind_layers(Ether, EoamPayload, type=0xbeef)
+
+
+
+
+
+f1 = Ether() / EoamPayload()
+print '0x%X' % f1.type
+
+
+f2 = Ether() / EoamPayload()
+print '0x%X' % f2.type
+
+f3 = Ether() / Dot1Q() / EoamPayload()
+
+print '0x%X' % f3.type
+print '0x%X' % f3.payload.type
+
+f4 = Ether() / Dot1Q() / Dot1Q() / EoamPayload()
+
+print '0x%X' % f4.type
+print '0x%X' % f4.payload.type
+print '0x%X' % f4.payload.payload.type
diff --git a/voltha/adapters/tibit_onu/EOAM.py b/voltha/adapters/tibit_onu/EOAM.py
new file mode 100644
index 0000000..3f7e3c9
--- /dev/null
+++ b/voltha/adapters/tibit_onu/EOAM.py
@@ -0,0 +1,214 @@
+#!/usr/bin/env python
+#--------------------------------------------------------------------------#
+# Copyright (C) 2015 - 2016 by Tibit Communications, Inc.                  #
+# All rights reserved.                                                     #
+#                                                                          #
+#    _______ ____  _ ______                                                #
+#   /_  __(_) __ )(_)_  __/                                                #
+#    / / / / __  / / / /                                                   #
+#   / / / / /_/ / / / /                                                    #
+#  /_/ /_/_____/_/ /_/                                                     #
+#                                                                          #
+#--------------------------------------------------------------------------#
+""" EOAM protocol implementation in scapy """
+from scapy.layers.inet import IP
+
+TIBIT_VERSION_NUMBER = '1.1.2'
+
+import argparse
+import logging
+
+logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
+from scapy.layers.l2 import Ether, Dot1Q
+from scapy.sendrecv import sendp
+
+import fcntl  # for get hw address
+
+# TODO should remove import *
+from EOAM_TLV import *
+
+EOAM_MULTICAST_ADDRESS = '01:80:c2:00:00:02'
+IGMP_MULTICAST_ADDRESS = '01:00:5e:00:00:01'   # for test
+
+class EOAM():
+    """ EOAM frame layer """
+    def __init__(self, ctag=None, dryrun=False, stag=None,
+                 verbose=False, etype='8809',
+                 dst=EOAM_MULTICAST_ADDRESS,
+                 hexdump=False, interface='eth0',
+                 sleep=2.0):
+        self.verbose = verbose
+        self.dst = dst
+        self.dryrun = dryrun
+        self.hexdump = hexdump
+        self.interface = interface
+        self.etype = int(etype, 16)
+        self.stag = stag
+        self.ctag = ctag
+        self.sleep = sleep
+        if (self.verbose == True):
+            print("=== Settings ================")
+            print("ctag      = %s" % self.ctag)
+            print("stag      = %s" % self.stag)
+            print("dst       = %s" % self.dst)
+            print("dryrun    = %s" % self.dryrun)
+            print("hexdump   = %s" % self.hexdump)
+            print("interface = %s" % self.interface)
+            print("etype     = 0x%04x" % self.etype)
+            print("verbose   = %s" % self.verbose)
+            print("sleep     = %d" % self.sleep)
+            print("=== END Settings ============")
+
+    def send_frame(self, frame_body):
+        PACKET = Ether()
+        PACKET.dst = self.dst
+        PACKET.src = self.getHwAddr(self.interface)
+        if self.stag:
+            # WARNING: September/2016: This should be 0x88a8, but the Intel 10G
+            # hardware I am currently using does not support receiving a TPID of
+            # 0x88a8. So, I send double CTAGs, and I usually set this to 0x8100.
+            # (NOTE: The Intel hardware can send a TPID of 0x88a8)
+            PACKET.type = 0x8100
+            if self.ctag:
+                PACKET/=Dot1Q(type=0x8100,vlan=int(self.stag))
+                PACKET/=Dot1Q(type=self.etype,vlan=int(self.ctag))
+            else:
+                PACKET/=Dot1Q(type=self.etype,vlan=int(self.stag))
+        else:
+            if self.ctag:
+                PACKET.type = 0x8100
+                PACKET/=Dot1Q(type=self.etype,vlan=int(self.ctag))
+            else:
+                PACKET.type = self.etype
+#            PACKET/=Dot1Q(type=self.etype, vlan=int(self.ctag))
+        PACKET/=SlowProtocolsSubtype()/FlagsBytes()/OAMPDU()
+        PACKET/=frame_body
+        PACKET/=EndOfPDU()
+        if (self.verbose == True):
+            PACKET.show()
+            print '###[ Frame Length %d (before padding) ]###' % len(PACKET)
+        if (self.hexdump == True):
+            print hexdump(PACKET)
+        if (self.dryrun != True):
+            sendp(PACKET, iface=self.interface)
+            time.sleep(self.sleep)
+        return PACKET
+
+    def get_request(self, TLV):
+        return self.send_frame(CablelabsOUI()/DPoEOpcode_GetRequest()/TLV)
+
+    def set_request(self, TLV):
+        return self.send_frame(CablelabsOUI()/DPoEOpcode_SetRequest()/TLV)
+
+    def send_multicast_register(self, TLV):
+        '''
+        Note, for mulicast, the standard specifies a register message
+        with ActionFlags of either Register or Deregister
+        '''
+        return self.send_frame(CablelabsOUI()/DPoEOpcode_MulticastRegister()/TLV)
+
+    def set_request_broadcom(self, TLV):
+        return self.send_frame(BroadcomOUI()/DPoEOpcode_SetRequest()/TLV)
+
+    def getHwAddr(self, ifname):
+        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+        info = fcntl.ioctl(s.fileno(), 0x8927,  struct.pack('256s', ifname[:15]))
+        return ':'.join(['%02x' % ord(char) for char in info[18:24]])
+
+
+class EoamPayload(Packet):
+    name = 'EOAM Payload'
+    fields_desc = [
+        ByteEnumField("subtype", 0x03, SlowProtocolsSubtypeEnum),
+        XShortField("flags", 0x0050),
+        XByteField("opcode", 0xfe),
+        PacketField("body", None, Packet),
+        BitEnumField("type", 0x00, 7, TLV_dictionary),
+        BitField("length", 0x00, 9)
+    ]
+
+#    def get_request(self, TLV):
+#        return self.payload(CablelabsOUI()/DPoEOpcode_GetRequest()/TLV)
+
+#    def set_request(self, TLV):
+#        return self.payload(CablelabsOUI()/DPoEOpcode_SetRequest()/TLV)
+
+bind_layers(Ether, EoamPayload, type=0x8809)
+
+
+
+if __name__ == "__main__":
+    parser = argparse.ArgumentParser()
+    parser.add_argument('-d', '--dst', dest='dst', action='store', default=EOAM_MULTICAST_ADDRESS,
+                        help='MAC destination (default: %s)' % EOAM_MULTICAST_ADDRESS)
+    parser.add_argument('-e', '--etype', dest='etype', action='store', default='8809',
+                        help='EtherType value (default: 0x8809)')
+    parser.add_argument('-i', '--interface', dest='interface', action='store', default='eth0',
+                        help='ETH interface to send (default: eth0)')
+    parser.add_argument('-s', '--stag', dest='stag', action='store', default=None,
+                        help='STAG value (default: None)')
+    parser.add_argument('-c', '--ctag', dest='ctag', action='store', default=None,
+                        help='CTAG value (default: None)')
+    parser.add_argument('-p', '--sleep', dest='sleep', action='store', default='1.0', type=float,
+                        help='SLEEP time after frame (default: 1.0 secs)')
+    parser.add_argument('-v', '--verbose', dest='verbose', action='store_true', default=False,
+                        help='verbose frame print out')
+    parser.add_argument('-x', '--hexdump', dest='hexdump', action='store_true', default=False,
+                        help='Hexdump the frame')
+    parser.add_argument('-y', '--dryrun', dest='dryrun', action='store_true', default=False,
+                        help='Dry run test, dont send - just print')
+
+    parser.add_argument('-t', '--test', dest='test', action='store_true', default=False,
+                        help='Run commands under test')
+    parser.add_argument('-r', '--critical', dest='critical', action='store_true', default=False,
+                        help='Send the critical OAM set of set_request()')
+    parser.add_argument('-ta', '--test_add', dest='test_add', action='store_true', default=False,
+                        help='Run commands under test')
+    parser.add_argument('-td', '--test_del', dest='test_del', action='store_true', default=False,
+                        help='Run commands under test')
+    parser.add_argument('-tc', '--test_clr', dest='test_clr', action='store_true', default=False,
+                        help='Run commands under test')
+
+    args = parser.parse_args()
+
+    if (args.dryrun == True):
+        args.sleep = 0.0
+
+    eoam = EOAM(
+        dryrun=args.dryrun,
+        dst=args.dst,
+        etype=args.etype,
+        hexdump=args.hexdump,
+        interface=args.interface,
+        stag=args.stag,
+        ctag=args.ctag,
+        verbose=args.verbose,
+        sleep=args.sleep
+        )
+
+    if (not args.critical
+        and not args.test
+        and not args.test_add
+        and not args.test_del
+        and not args.test_clr):
+        print 'WARNING: *** No frames sent, please specify \'test\' or \'critical\', etc.  See --help'
+
+
+    if (args.test == True):
+        print 'SET - Multicast Register Message 01'
+        eoam.send_multicast_register(MulticastRegisterSet(MulticastLink=0x3fe0, UnicastLink=0x1008))
+
+        print 'SET - Multicast Deregister Message 02'
+        eoam.send_multicast_register(MulticastRegisterSet(ActionFlags="Deregister",MulticastLink=0x3fe0, UnicastLink=0x1008))
+
+    if (args.test_clr == True):
+        print 'SET Clear Static MAC Table -- User Port Object'
+        eoam.set_request(ClearStaticMacTable())
+
+    elif (args.test_add == True):
+        print 'SET Add Static MAC Address -- User Port Object'
+        eoam.set_request(AddStaticMacAddress(mac=IGMP_MULTICAST_ADDRESS))
+
+    elif (args.test_del == True):
+        print 'SET Delete Static MAC Address -- User Port Object'
+        eoam.set_request(DeleteStaticMacAddress(mac=IGMP_MULTICAST_ADDRESS))
diff --git a/voltha/adapters/tibit_onu/EOAM_TLV.py b/voltha/adapters/tibit_onu/EOAM_TLV.py
new file mode 100644
index 0000000..0928189
--- /dev/null
+++ b/voltha/adapters/tibit_onu/EOAM_TLV.py
@@ -0,0 +1,1033 @@
+#--------------------------------------------------------------------------#
+# Copyright (C) 2015 - 2016 by Tibit Communications, Inc.                  #
+# All rights reserved.                                                     #
+#                                                                          #
+#    _______ ____  _ ______                                                #
+#   /_  __(_) __ )(_)_  __/                                                #
+#    / / / / __  / / / /                                                   #
+#   / / / / /_/ / / / /                                                    #
+#  /_/ /_/_____/_/ /_/                                                     #
+#                                                                          #
+#--------------------------------------------------------------------------#
+
+from scapy.packet import *
+from scapy.fields import *
+
+# This library strives to be an implementation of the following standard:
+
+# DPoE-SP-OAMv1.0-IO8-140807 - DPoE OAM Extensions Specifications
+
+# This library may be used with PON devices for
+# configuration and provisioning.
+
+TIBIT_VERSION_NUMBER = '1.0.1'
+
+TLV_dictionary = {
+    0x00: "End EOAMPDU",
+    }
+
+SlowProtocolsSubtypeEnum = {0x03: "OAM"}
+
+### Multicast Action Flags
+MulticastActionFlagsEnum = {
+    0x02: "Deregister",
+    0x03: "Register"
+    }
+
+### Table 17 - DPoE Opcodes
+DPoEOpcodeEnum = {
+    0x01: "Get Request",
+    0x02: "Get Response",
+    0x03: "Set Request",
+    0x04: "Set Response",
+    0x05: "Dynamic IP Multicast Control",
+    0x06: "Multicast Register",
+    0x07: "Multicast Register Response",
+    }
+
+### Table 20 - DPoE Variable Response Codes
+DPoEVariableResponseCodes = {
+    0x80, "No Error",
+    0x81, "Too Long",
+    0x86, "Bad Parameters",
+    0x87, "No Resources",
+    0x88, "System Busy",
+    0xa0, "Undetermined Error",
+    0xa1, "Unsupported",
+    0xa2, "May Be Corrupted",
+    0xa3, "Hardware Failure",
+    0xa4, "Overflow",
+    }
+
+class SlowProtocolsSubtype(Packet):
+    """ Slow Protocols subtype"""
+    name = "Slow Protocols subtype"
+    fields_desc  = [ByteEnumField("subtype", 0x03, SlowProtocolsSubtypeEnum)]
+
+class FlagsBytes(Packet):
+    """ Two Bytes Reserved for 802.3 Flags"""
+    name = "FlagsBytes"
+    fields_desc  = [XShortField("flags", 0x0050)]
+
+class OAMPDU(Packet):
+    """ OAMPDU code: Organization Specific"""
+    name = "OAMPDU code: Organization Specific"
+    fields_desc  = [XByteField("opcode", 0xfe)]
+
+class CablelabsOUI(Packet):
+    """ Organizationally Unique Identifier (Cablelabs)"""
+    name = "Organizationally Unique Identifier (Cablelabs)"
+    fields_desc  = [XByteField("oui0", 0x00),
+                    XByteField("oui1", 0x10),
+                    XByteField("oui2", 0x00)]
+
+class BroadcomOUI(Packet):
+    """ Organizationally Unique Identifier (Broadcom)"""
+    name = "Organizationally Unique Identifier (Broadcom)"
+    fields_desc  = [XByteField("oui0", 0x00),
+                    XByteField("oui1", 0x0D),
+                    XByteField("oui2", 0xB6)]
+
+class DPoEOpcode_GetRequest(Packet):
+    """ DPoE Opcode"""
+    name = "DPoE Opcode"
+    fields_desc  = [ByteEnumField("opcode", 0x01, DPoEOpcodeEnum)]
+
+class DPoEOpcode_SetRequest(Packet):
+    """ DPoE Opcode"""
+    name = "DPoE Opcode"
+    fields_desc  = [ByteEnumField("opcode", 0x03, DPoEOpcodeEnum)]
+
+class DPoEOpcode_MulticastRegister(Packet):
+    """ DPoE Opcode"""
+    name = "DPoE Opcode"
+    fields_desc  = [ByteEnumField("opcode", 0x06, DPoEOpcodeEnum)]
+
+class DPoEOpcode_MulticastRegisterResponse(Packet):
+    """ DPoE Opcode"""
+    name = "DPoE Opcode"
+    fields_desc  = [ByteEnumField("opcode", 0x07, DPoEOpcodeEnum)]
+
+class MulticastRegisterSetSumitomo01(Packet):
+    """ Multicast Register: Multicast Register Set Sumitomo 01 """
+    name = "Multicast Register: Multicast Register Set Sumitomo 01"
+    fields_desc = [ByteEnumField("ActionFlags", 0x02, MulticastActionFlagsEnum),
+                   XShortField("MulticastLink", 0xfffe),
+                   XShortField("UnicastLink", 0x43dc),
+                   ]
+
+class MulticastRegisterSetSumitomo02(Packet):
+    """ Multicast Register: Multicast Register Set Sumitomo 02 """
+    name = "Multicast Register: Multicast Register Set Sumitomo 02"
+    fields_desc = [ByteEnumField("ActionFlags", 0x03, MulticastActionFlagsEnum),
+                   XShortField("MulticastLink", 0x43dd),
+                   XShortField("UnicastLink", 0x43dc),
+                   ]
+
+class MulticastRegisterSet(Packet):
+    """ Multicast Register: Multicast Register Set """
+    name = "Multicast Register: Multicast Register Set"
+    fields_desc = [ByteEnumField("ActionFlags", 0x03, MulticastActionFlagsEnum),
+                   XShortField("MulticastLink", 0x0000),
+                   XShortField("UnicastLink", 0x0000),
+                   ]
+####
+#### PORT OBJECTS
+####
+class DONUObject(Packet):
+    """ Object Context: D-ONU Object """
+    name = "Object Context: D-ONU Object"
+    fields_desc = [XByteField("branch", 0xD6),
+                   XShortField("leaf", 0x0000),
+                   XByteField("length", 1),
+                   XByteField("num", 0)
+                   ]
+
+class NetworkPortObject(Packet):
+    """ Object Context: Network Port Object """
+    name = "Object Context: Network Port Object"
+    fields_desc = [XByteField("branch", 0xD6),
+                   XShortField("leaf", 0x0001),
+                   XByteField("length", 1),
+                   XByteField("num", 0)
+                   ]
+
+class UnicastLogicalLink(Packet):
+    """ Object Context: Unicast Logical Link """
+    name = "Object Context: Unicast Logical Link"
+    fields_desc = [XByteField("branch", 0xD6),
+                   XShortField("leaf", 0x0002),
+                   XByteField("length", 1),
+                   XByteField("number", 0)
+                   ]
+
+class UserPortObject(Packet):
+    """ Object Context: User Port Object """
+    name = "Object Context: User Port Object"
+    fields_desc = [XByteField("branch", 0xD6),
+                   XShortField("leaf", 0x0003),
+                   XByteField("length", 1),
+                   XByteField("number", 0)
+                   ]
+
+class QueueObject(Packet):
+    """ Object Context: Queue Object """
+    name = "Object Context: Queue Object"
+    fields_desc = [XByteField("branch", 0xD6),
+                   XShortField("leaf", 0x0004),
+                   XByteField("length", 2),
+                   XByteField("instance", 0),
+                   XByteField("number", 0)
+                   ]
+
+
+####
+#### 0x09 - BRANCH ATTRIBUTES
+####
+class PhyAdminControl(Packet):
+    """ Variable Descriptor: Phy Admin Control """
+    name = "Variable Descriptor: Phy Admin Control"
+    fields_desc = [XByteField("branch", 0x09),
+                   XShortField("leaf", 0x0005),
+                   ]
+
+class PhyAdminControlEnableSet(Packet):
+    """ Variable Descriptor: Phy Admin Control Enable """
+    name = "Variable Descriptor: Phy Admin Control Enable"
+    fields_desc = [XByteField("branch", 0x09),
+                   XShortField("leaf", 0x0005),
+                   XByteField("length", 1),
+                   XByteField("value", 2)
+                   ]
+
+class PhyAdminControlDisableSet(Packet):
+    """ Variable Descriptor: Phy Admin Control Disable """
+    name = "Variable Descriptor: Phy Admin Control Disable"
+    fields_desc = [XByteField("branch", 0x09),
+                   XShortField("leaf", 0x0005),
+                   XByteField("length", 1),
+                   XByteField("value", 1)
+                   ]
+
+####
+#### 0xd7 - BRANCH ATTRIBUTES
+####
+class DeviceId(Packet):
+    """ Variable Descriptor: Device ID """
+    name = "Variable Descriptor: Device ID"
+    fields_desc = [XByteField("branch", 0xD7),
+                   XShortField("leaf", 0x0002)]
+
+class FirmwareInfo(Packet):
+    """ Variable Descriptor: Firmware Info """
+    name = "Variable Descriptor: Firmware Info"
+    fields_desc = [XByteField("branch", 0xD7),
+                   XShortField("leaf", 0x0003)]
+
+class ChipsetInfo(Packet):
+    """ Variable Descriptor: Chipset Info """
+    name = "Variable Descriptor: Chipset Info"
+    fields_desc = [XByteField("branch", 0xD7),
+                   XShortField("leaf", 0x0004)]
+
+class DateOfManufacture(Packet):
+    """ Variable Descriptor: Date of Manufacture """
+    name = "Variable Descriptor: Date of Manufacture"
+    fields_desc = [XByteField("branch", 0xD7),
+                   XShortField("leaf", 0x0005)]
+
+class MaxLogicalLinks(Packet):
+    """ Variable Descriptor: Max Logical Links """
+    name = "Variable Descriptor: Max Logical Links"
+    fields_desc = [XByteField("branch", 0xD7),
+                   XShortField("leaf", 0x0007)]
+
+class NumberOfNetworkPorts(Packet):
+    """ Variable Descriptor: Number of Network Ports """
+    name = "Variable Descriptor: Number of Network Ports"
+    fields_desc = [XByteField("branch", 0xD7),
+                   XShortField("leaf", 0x0008)]
+
+class NumberOfS1Interfaces(Packet):
+    """ Variable Descriptor: Number of S1 Interfaces """
+    name = "Variable Descriptor: Number of S1 Interfaces"
+    fields_desc = [XByteField("branch", 0xD7),
+                   XShortField("leaf", 0x0009)]
+
+class DONUPacketBuffer(Packet):
+    """ Variable Descriptor: D-ONU Packet Buffer """
+    name = "Variable Descriptor: D-ONU Packet Buffer"
+    fields_desc = [XByteField("branch", 0xD7),
+                   XShortField("leaf", 0x000a)]
+
+class ReportThresholds(Packet):
+    """ Variable Descriptor: Report Thresholds """
+    name = "Variable Descriptor: Report Thresholds"
+    fields_desc = [XByteField("branch", 0xD7),
+                   XShortField("leaf", 0x000b),
+                   ]
+
+class ReportThresholdsSet(Packet):
+    """ Variable Descriptor: Report Thresholds Set """
+    name = "Variable Descriptor: Report Thresholds Set"
+    fields_desc = [XByteField("branch", 0xD7),
+                   XShortField("leaf", 0x000b),
+                   XByteField("length", 0x0a),
+                   XByteField("num_queue_sets", 4),
+                   XByteField("values", 1),
+                   XShortField("threshold0", 0x800),
+                   XShortField("threshold1", 0x1000),
+                   XShortField("threshold2", 0x1800),
+                   XShortField("threshold3", 0x2000),
+                   ]
+
+class UnicastLogicalLinkReportThresholdsSet(Packet):
+    """ Variable Descriptor: Report Thresholds Unicast Logical Link Set"""
+    name = "Variable Descriptor: Report Thresholds Unicast Logical Link Set"
+    fields_desc = [XByteField("branch", 0xD7),
+                   XShortField("leaf", 0x000b),
+                   XByteField("length", 0x0a),
+                   XByteField("num_queue_sets", 4),
+                   XByteField("values", 1),
+                   XShortField("threshold0", 0x2800),
+                   XShortField("threshold1", 0x5000),
+                   XShortField("threshold2", 0x7800),
+                   XShortField("threshold3", 0xa000),
+                   ]
+
+class LogicalLinkForwarding(Packet):
+    """ Variable Descriptor: Logical Link Forwarding """
+    name = "Variable Descriptor: Logical Link Forwarding"
+    fields_desc = [XByteField("branch", 0xD7),
+                   XShortField("leaf", 0x000c),
+                   ]
+
+class OamFrameRate(Packet):
+    """ Variable Descriptor: OAM Frame Rate """
+    name = "Variable Descriptor: OAM Frame Rate"
+    fields_desc = [XByteField("branch", 0xD7),
+                   XShortField("leaf", 0x000d),
+                   ]
+
+class OamFrameRateSet(Packet):
+    """ Variable Descriptor: OAM Frame Rate """
+    name = "Variable Descriptor: OAM Frame Rate"
+    fields_desc = [XByteField("branch", 0xD7),
+                   XShortField("leaf", 0x000d),
+                   XByteField("length", 2),
+                   XByteField("max", 12),
+                   XByteField("min", 10),
+                   ]
+
+class OnuManufacturerOrganizationName(Packet):
+    """ Variable Descriptor: ONU Manufacturer Organization Name """
+    name = "Variable Descriptor: ONU Manufacturer Organization Name"
+    fields_desc = [XByteField("branch", 0xD7),
+                   XShortField("leaf", 0x000e),
+                   ]
+
+class FirmwareMfgTimeVaryingControls(Packet):
+    """ Variable Descriptor: Firmware Mfg Time Varying Controls """
+    name = "Variable Descriptor: Firmware Mfg Time Varying Controls"
+    fields_desc = [XByteField("branch", 0xD7),
+                   XShortField("leaf", 0x000f),
+                   ]
+
+class VendorName(Packet):
+    """ Variable Descriptor: Vendor Name """
+    name = "Variable Descriptor: Vendor Name"
+    fields_desc = [XByteField("branch", 0xD7),
+                   XShortField("leaf", 0x0011),
+                   ]
+
+class ModelNumber(Packet):
+    """ Variable Descriptor: Model Number """
+    name = "Variable Descriptor: Model Number"
+    fields_desc = [XByteField("branch", 0xD7),
+                   XShortField("leaf", 0x0012),
+                   ]
+
+class HardwareVersion(Packet):
+    """ Variable Descriptor: Hardware Version """
+    name = "Variable Descriptor: Hardware Version"
+    fields_desc = [XByteField("branch", 0xD7),
+                   XShortField("leaf", 0x0013),
+                   ]
+
+class EponMode(Packet):
+    """ Variable Descriptor: EPON Mode """
+    name = "Variable Descriptor: EPON Mode"
+    fields_desc = [XByteField("branch", 0xD7),
+                   XShortField("leaf", 0x0014),
+                   ]
+
+class DynamicAddressAgeLimit(Packet):
+    """ Variable Descriptor: Dynamic Address Age Limit """
+    name = "Variable Descriptor: Dynamic Address Age Limit"
+    fields_desc = [XByteField("branch", 0xD7),
+                   XShortField("leaf", 0x0102),
+                   ]
+
+class DynamicAddressAgeLimitSet(Packet):
+    """ Variable Descriptor: Dynamic Address Age Limit Set """
+    name = "Variable Descriptor: Dynamic Address Age Limit Set"
+    fields_desc = [XByteField("branch", 0xD7),
+                   XShortField("leaf", 0x0102),
+                   XByteField("length", 2),
+                   XShortField("value", 0x0000),
+                   ]
+
+class DynamicMacTable(Packet):
+    """ Variable Descriptor: Dynamic MAC Table """
+    name = "Variable Descriptor: Dynamic MAC Table"
+    fields_desc = [XByteField("branch", 0xD7),
+                   XShortField("leaf", 0x0103),
+                   ]
+
+class StaticMacTable(Packet):
+    """ Variable Descriptor: Static MAC Table """
+    name = "Variable Descriptor: Static MAC Table"
+    fields_desc = [XByteField("branch", 0xD7),
+                   XShortField("leaf", 0x0104),
+                   ]
+
+class SourceAddressAdmissionControl(Packet):
+    """ Variable Descriptor: Source Address Admission Control """
+    name = "Variable Descriptor: Source Address Admission Control"
+    fields_desc = [XByteField("branch", 0xD7),
+                   XShortField("leaf", 0x0106),
+                   ]
+
+class SourceAddressAdmissionControlSet(Packet):
+    """ Variable Descriptor: Source Address Admission Control Set """
+    name = "Variable Descriptor: Source Address Admission Control Set"
+    fields_desc = [XByteField("branch", 0xD7),
+                   XShortField("leaf", 0x0106),
+                   XByteField("length", 1),
+                   XByteField("value", 1),
+                   ]
+
+class MacLearningMinGuarantee(Packet):
+    """ Variable Descriptor: MAC Learning MIN Guarantee """
+    name = "Variable Descriptor: MAC Learning MIN Guarantee"
+    fields_desc = [XByteField("branch", 0xD7),
+                   XShortField("leaf", 0x0107),
+                   ]
+
+class MacLearningMinGuaranteeSet(Packet):
+    """ Variable Descriptor: MAC Learning MIN Guarantee Set """
+    name = "Variable Descriptor: MAC Learning MIN Guarantee Set"
+    fields_desc = [XByteField("branch", 0xD7),
+                   XShortField("leaf", 0x0107),
+                   XByteField("length", 2),
+                   XShortField("value", 0),
+                   ]
+
+class MacLearningMaxAllowed(Packet):
+    """ Variable Descriptor: MAC Learning MAX Allowed """
+    name = "Variable Descriptor: MAC Learning MAX Allowed"
+    fields_desc = [XByteField("branch", 0xD7),
+                   XShortField("leaf", 0x0108),
+                   ]
+
+class MacLearningMaxAllowedSet(Packet):
+    """ Variable Descriptor: MAC Learning MAX Allowed Set """
+    name = "Variable Descriptor: MAC Learning MAX Allowed Set"
+    fields_desc = [XByteField("branch", 0xD7),
+                   XShortField("leaf", 0x0108),
+                   XByteField("length", 2),
+                   XShortField("value", 0x0010),
+                   ]
+
+class MacLearningAggregateLimit(Packet):
+    """ Variable Descriptor: MAC Learning Aggregate Limit """
+    name = "Variable Descriptor: MAC Learning Aggregate Limit"
+    fields_desc = [XByteField("branch", 0xD7),
+                   XShortField("leaf", 0x0109),
+                   ]
+
+class MacLearningAggregateLimitSet(Packet):
+    """ Variable Descriptor: MAC Learning Aggregate Limit Set """
+    name = "Variable Descriptor: MAC Learning Aggregate Limit Set"
+    fields_desc = [XByteField("branch", 0xD7),
+                   XShortField("leaf", 0x0109),
+                   XByteField("length", 2),
+                   XShortField("value", 0x0040),
+                   ]
+
+class FloodUnknown(Packet):
+    """ Variable Descriptor: Flood Unknown """
+    name = "Variable Descriptor: Flood Unknown"
+    fields_desc = [XByteField("branch", 0xD7),
+                   XShortField("leaf", 0x010b),
+                   ]
+
+class FloodUnknownSet(Packet):
+    """ Variable Descriptor: Flood Unknown Set """
+    name = "Variable Descriptor: Flood Unknown Set"
+    fields_desc = [XByteField("branch", 0xD7),
+                   XShortField("leaf", 0x010b),
+                   XByteField("length", 1),
+                   XByteField("value", 1),
+                   ]
+
+class LocalSwitching(Packet):
+    """ Variable Descriptor: Local Switching """
+    name = "Variable Descriptor: Local Switching"
+    fields_desc = [XByteField("branch", 0xD7),
+                   XShortField("leaf", 0x010c),
+                   ]
+
+class LocalSwitchingSet(Packet):
+    """ Variable Descriptor: Local Switching Set """
+    name = "Variable Descriptor: Local Switching Set"
+    fields_desc = [XByteField("branch", 0xD7),
+                   XShortField("leaf", 0x010c),
+                   XByteField("length", 1),
+                   XByteField("value", 0),
+                   ]
+
+class LLIDQueueConfiguration(Packet):
+    """ Variable Descriptor: LLID Queue Configuration """
+    name = "Variable Descriptor: LLID Queue Configuration"
+    fields_desc = [XByteField("branch", 0xD7),
+                   XShortField("leaf", 0x010d),
+                   ]
+
+class LLIDQueueConfigurationSet(Packet):
+    """ Variable Descriptor: LLID Queue Configuration """
+    name = "Variable Descriptor: LLID Queue Configuration"
+    fields_desc = [XByteField("branch", 0xD7),
+                   XShortField("leaf", 0x010d),
+                   XByteField("length", 6),
+                   XByteField("numLLID", 1),
+                   XByteField("LLID0-numq", 1),
+                   XByteField("l0Q0-size",0xa0),
+                   XByteField("numPort", 1),
+                   XByteField("Port0-numq", 1),
+                   XByteField("p0Q0-size",0xa0),
+                   ]
+
+class FirmwareFilename(Packet):
+    """ Variable Descriptor: Firmware Filename """
+    name = "Variable Descriptor: Firmware Filename"
+    fields_desc = [XByteField("branch", 0xD7),
+                   XShortField("leaf", 0x010e),
+                   ]
+####
+#### 0xD9 - MAC Table Operations - Dynamic and Static
+####
+
+class ClearDynamicMacTable(Packet):
+    """ Variable Descriptor: Clear Dynamic MAC Table """
+    name = "Variable Descriptor: Clear Dynamic MAC Table"
+    fields_desc = [XByteField("branch", 0xD9),
+                   XShortField("leaf", 0x0101),
+                   ]
+
+class AddDynamicMacAddress(Packet):
+    """ Variable Descriptor: Add Dynamic MAC Address """
+    name = "Variable Descriptor: Add Dynamic MAC Address"
+    fields_desc = [XByteField("branch", 0xD9),
+                   XShortField("leaf", 0x0102),
+                   ]
+
+class DeleteDynamicMacAddress(Packet):
+    """ Variable Descriptor: Delete Dynamic MAC Address """
+    name = "Variable Descriptor: Delete Dynamic MAC Address"
+    fields_desc = [XByteField("branch", 0xD9),
+                   XShortField("leaf", 0x0103),
+                   ]
+
+class ClearStaticMacTable(Packet):
+    """ Variable Descriptor: Clear Static MAC Table """
+    name = "Variable Descriptor: Clear Static MAC Table"
+    fields_desc = [XByteField("branch", 0xD9),
+                   XShortField("leaf", 0x0104),
+                   ]
+
+class AddStaticMacAddress(Packet):
+    """ Variable Descriptor: Add Static MAC Address """
+    name = "Variable Descriptor: Add Static MAC Address"
+    fields_desc = [XByteField("branch", 0xD9),
+                   XShortField("leaf", 0x0105),
+                   ByteField("length", 6),
+                   MACField("mac", "01:00:5e:00:00:00"),
+                   ]
+
+class DeleteStaticMacAddress(Packet):
+    """ Variable Descriptor: Delete Static MAC Address """
+    name = "Variable Descriptor: Delete Static MAC Address"
+    fields_desc = [XByteField("branch", 0xD9),
+                   XShortField("leaf", 0x0106),
+                   ByteField("length", 6),
+                   MACField("mac", "01:00:5e:00:00:00"),
+                   ]
+
+####
+#### 0xd7 - STATISTICS
+####
+
+class RxFrame_512_1023(Packet):
+    """ Variable Descriptor: RxFrame_512_1023 """
+    name = "Variable Descriptor: RxFrame_512_1023"
+    fields_desc = [XByteField("branch", 0xD7),
+                   XShortField("leaf", 0x0208),
+                   ]
+
+class TxFrame_512_1023(Packet):
+    """ Variable Descriptor: TxFrame_512_1023 """
+    name = "Variable Descriptor: TxFrame_512_1023"
+    fields_desc = [XByteField("branch", 0xD7),
+                   XShortField("leaf", 0x020f),
+                   ]
+
+class FramesDropped(Packet):
+    """ Variable Descriptor: Frames Dropped """
+    name = "Variable Descriptor: Frames Dropped"
+    fields_desc = [XByteField("branch", 0xD7),
+                   XShortField("leaf", 0x0214),
+                   ]
+
+class BytesDropped(Packet):
+    """ Variable Descriptor: Bytes Dropped """
+    name = "Variable Descriptor: Bytes Dropped"
+    fields_desc = [XByteField("branch", 0xD7),
+                   XShortField("leaf", 0x0215),
+                   ]
+
+class TxBytesUnused(Packet):
+    """ Variable Descriptor: Tx Bytes Unused """
+    name = "Variable Descriptor: Tx Bytes Unused"
+    fields_desc = [XByteField("branch", 0xD7),
+                   XShortField("leaf", 0x0217),
+                   ]
+
+class TxL2Errors(Packet):
+    """ Variable Descriptor: TxL2Errors """
+    name = "Variable Descriptor: TxL2Errors"
+    fields_desc = [XByteField("branch", 0xD7),
+                   XShortField("leaf", 0x0235),
+                   ]
+
+class RxL2Errors(Packet):
+    """ Variable Descriptor: RxL2Errors """
+    name = "Variable Descriptor: RxL2Errors"
+    fields_desc = [XByteField("branch", 0xD7),
+                   XShortField("leaf", 0x0236),
+                   ]
+
+####
+#### 0xD7 - Alarm Reporting
+####
+
+class AlarmReporting(Packet):
+    """ Variable Descriptor: Alarm Reporting """
+    name = "Variable Descriptor: Alarm Reporting"
+    fields_desc = [XByteField("branch", 0xD7),
+                   XShortField("leaf", 0x0303),
+                   ]
+
+class AlarmReportingSet(Packet):
+    """ Variable Descriptor: Alarm Reporting Set """
+    name = "Variable Descriptor: Alarm Reporting Set"
+    fields_desc = [XByteField("branch", 0xD7),
+                   XShortField("leaf", 0x0303),
+                   XByteField("length", 6),
+                   XShortField("LOS", 0x1101),
+                   XShortField("KeyExchange", 0x1201),
+                   XShortField("PortDisbled", 0x2101),
+                   ]
+
+####
+#### 0xD7 - Encryption/ FEC/ and Queue CIR/EIR
+####
+class EncryptionMode(Packet):
+    """ Variable Descriptor: Encryption Mode """
+    name = "Variable Descriptor: Encryption Mode"
+    fields_desc = [XByteField("branch", 0xD7),
+                   XShortField("leaf", 0x0402),
+                   ]
+
+class EncryptionModeSet(Packet):
+    """ Variable Descriptor: Encryption Mode Set """
+    name = "Variable Descriptor: Encryption Mode Set"
+    fields_desc = [XByteField("branch", 0xD7),
+                   XShortField("leaf", 0x0402),
+                   XByteField("length", 1),
+                   XByteField("value", 0),
+                   ]
+
+class IpmcForwardingRuleConfiguration(Packet):
+    """ Variable Descriptor: IPMC Forwarding Rule Configuration """
+    name = "Variable Descriptor: IPMC Forwarding Rule Configuration"
+    fields_desc = [XByteField("branch", 0xD7),
+                   XShortField("leaf", 0x0505),
+                   XByteField("length", 2),
+                   XShortField("value", 0x0000),
+                   ]
+
+class QueueCommittedInformationRate(Packet):
+    """ Variable Descriptor: Queue Committed Information Rate """
+    name = "Variable Descriptor: Queue Committed Information Rate"
+    fields_desc = [XByteField("branch", 0xD7),
+                   XShortField("leaf", 0x0604),
+                   ]
+
+class QueueCommittedInformationRateSet(Packet):
+    """ Variable Descriptor: Queue Committed Information Rate Set """
+    name = "Variable Descriptor: Queue Committed Information Rate Set"
+    fields_desc = [XByteField("branch", 0xD7),
+                   XShortField("leaf", 0x0604),
+                   XByteField("length", 6),
+                   XShortField("burst", 0x0fff),
+                   XShortField("CIR_UPPER", 0x0000),
+                   XShortField("CIR_LOWER", 0xffff),
+                   ]
+
+class FECMode(Packet):
+    """ Variable Descriptor: FEC Mode """
+    name = "Variable Descriptor: FEC Mode"
+    fields_desc = [XByteField("branch", 0xD7),
+                   XShortField("leaf", 0x0605),
+                   ]
+
+class FECModeSet(Packet):
+    """ Variable Descriptor: FEC Mode """
+    name = "Variable Descriptor: FEC Mode"
+    fields_desc = [XByteField("branch", 0xD7),
+                   XShortField("leaf", 0x0605),
+                   ]
+
+class MediaType(Packet):
+    """ Variable Descriptor: Media Type """
+    name = "Variable Descriptor: Media Type"
+    fields_desc = [XByteField("branch", 0xD7),
+                   XShortField("leaf", 0x0822),
+                   ]
+
+
+####
+#### 0xD7 - Port Ingress Rules
+####
+class PortIngressRule(Packet):
+    """ Variable Descriptor: Port Ingress Rule """
+    name = "Variable Descriptor: Port Ingress Rule"
+    fields_desc = [XByteField("branch", 0xD7),
+                   XShortField("leaf", 0x0501),
+                   ]
+
+class PortIngressRuleHeader(Packet):
+    """ Variable Descriptor: Port Ingress Rule Header """
+    name = "Variable Descriptor: Port Ingress Rule Header"
+    fields_desc = [
+        XByteField("branch", 0xD7),
+        XShortField("leaf", 0x0501),
+        ByteField("length", 2),
+        XByteField("header", 1),
+        XByteField("precedence", 00),
+        ]
+
+class PortIngressRuleClauseMatchLength00(Packet):
+    """ Variable Descriptor: Port Ingress Rule Clause """
+    name = "Variable Descriptor: Port Ingress Rule Clause"
+    fields_desc = [
+        XByteField("branch", 0xD7),
+        XShortField("leaf", 0x0501),
+        ByteField("length", 7),
+        XByteField("clause", 2),
+        XByteField("fieldcode", 0),
+        XByteField("fieldinstance", 0),
+        XByteField("msbmask", 0),
+        XByteField("lsbmask", 0),
+        XByteField("operator", 0),
+        XByteField("matchlength", 0),
+        ]
+
+class PortIngressRuleClauseMatchLength01(Packet):
+    """ Variable Descriptor: Port Ingress Rule Clause """
+    name = "Variable Descriptor: Port Ingress Rule Clause"
+    fields_desc = [
+        XByteField("branch", 0xD7),
+        XShortField("leaf", 0x0501),
+        ByteField("length", 8),
+        XByteField("clause", 2),
+        XByteField("fieldcode", 0),
+        XByteField("fieldinstance", 0),
+        XByteField("msbmask", 0),
+        XByteField("lsbmask", 0),
+        XByteField("operator", 0),
+        XByteField("matchlength", 1),
+        XByteField("match0", 0),
+        ]
+
+class PortIngressRuleClauseMatchLength02(Packet):
+    """ Variable Descriptor: Port Ingress Rule Clause """
+    name = "Variable Descriptor: Port Ingress Rule Clause"
+    fields_desc = [
+        XByteField("branch", 0xD7),
+        XShortField("leaf", 0x0501),
+        ByteField("length", 9),
+        XByteField("clause", 2),
+        XByteField("fieldcode", 0),
+        XByteField("fieldinstance", 0),
+        XByteField("msbmask", 0),
+        XByteField("lsbmask", 0),
+        XByteField("operator", 0),
+        XByteField("matchlength", 2),
+        XByteField("match0", 0),
+        XByteField("match1", 0),
+        ]
+
+
+class PortIngressRuleClauseMatchLength06(Packet):
+    """ Variable Descriptor: Port Ingress Rule Clause """
+    name = "Variable Descriptor: Port Ingress Rule Clause"
+    fields_desc = [
+        XByteField("branch", 0xD7),
+        XShortField("leaf", 0x0501),
+        ByteField("length", 13),
+        XByteField("clause", 2),
+        XByteField("fieldcode", 0),
+        XByteField("fieldinstance", 0),
+        XByteField("msbmask", 0),
+        XByteField("lsbmask", 0),
+        XByteField("operator", 0),
+        XByteField("matchlength", 6),
+        XByteField("match0", 0x01),
+        XByteField("match1", 0x80),
+        XByteField("match2", 0xc2),
+        XByteField("match3", 0x00),
+        XByteField("match4", 0x00),
+        XByteField("match5", 0x00),
+        ]
+
+class PortIngressRuleResultForward(Packet):
+    """ Variable Descriptor: Port Ingress Rule Result Forward """
+    name = "Variable Descriptor: Port Ingress Rule Result Forward"
+    fields_desc = [
+        XByteField("branch", 0xD7),
+        XShortField("leaf", 0x0501),
+        ByteField("length", 2),
+        XByteField("result", 3),
+        XByteField("forward", 2),
+        ]
+
+class PortIngressRuleResultDiscard(Packet):
+    """ Variable Descriptor: Port Ingress Rule Result Discard """
+    name = "Variable Descriptor: Port Ingress Rule Result Discard"
+    fields_desc = [
+        XByteField("branch", 0xD7),
+        XShortField("leaf", 0x0501),
+        ByteField("length", 2),
+        XByteField("result", 3),
+        XByteField("discard", 1),
+        ]
+
+class PortIngressRuleResultQueue(Packet):
+    """ Variable Descriptor: Port Ingress Rule Result Queue """
+    name = "Variable Descriptor: Port Ingress Rule Result Queue"
+    fields_desc = [
+        XByteField("branch", 0xD7),
+        XShortField("leaf", 0x0501),
+        ByteField("length", 6),
+        XByteField("result", 3),
+        XByteField("queuerule", 3),
+        XShortField("objecttype", 0x0000),
+        XByteField("instance", 0),
+        XByteField("queuenum", 0),
+        ]
+
+class PortIngressRuleTerminator(Packet):
+    """ Variable Descriptor: Port Ingress Rule Terminator """
+    name = "Variable Descriptor: Port Ingress Rule Terminator"
+    fields_desc = [
+        XByteField("branch", 0xD7),
+        XShortField("leaf", 0x0501),
+        ByteField("length", 1),
+        XByteField("terminator", 0),
+        ]
+
+class CustomField(Packet):
+    """ Variable Descriptor: Custom Field """
+    name = "Variable Descriptor: Custom Field"
+    fields_desc = [XByteField("branch", 0xD7),
+                   XShortField("leaf", 0x0502),
+                   XByteField("length", 1),
+                   XByteField("value", 0),
+                   ]
+
+class CustomFieldEtherType(Packet):
+    """ Variable Descriptor: Custom Field EtherType """
+    name = "Variable Descriptor: Custom Field EtherType"
+    fields_desc = [XByteField("branch", 0xD7),
+                   XShortField("leaf", 0x0502),
+                   XByteField("length", 6),
+                   XByteField("fieldcode", 0x19),
+                   XByteField("layerselect", 2),
+                   XByteField("dwordoffset", 0),
+                   XByteField("lsb", 0),
+                   XByteField("width", 0x10),
+                   XByteField("numclauses", 0),
+                   ]
+
+class CustomFieldGenericL3(Packet):
+    """ Variable Descriptor: Custom Field Generic L3 """
+    name = "Variable Descriptor: Custom Field Generic L3"
+    fields_desc = [XByteField("branch", 0xD7),
+                   XShortField("leaf", 0x0502),
+                   XByteField("length", 6),
+                   XByteField("fieldcode", 0x1a),
+                   XByteField("layerselect", 8),
+                   XByteField("dwordoffset", 0),
+                   XByteField("lsb", 0x18),
+                   XByteField("width", 0x8),
+                   XByteField("numclauses", 0),
+                   ]
+
+####
+#### 0xD9 - Port Ingress Rules
+####
+
+class ClearPortIngressRules(Packet):
+    """ Variable Descriptor: Clear Port Ingress Rule """
+    name = "Variable Descriptor: Clear Port Ingress Rule"
+    fields_desc = [XByteField("branch", 0xD9),
+                   XShortField("leaf", 0x0501),
+                   XByteField("length", 1),
+                   XByteField("value", 0),
+                   ]
+
+class AddPortIngressRule(Packet):
+    """ Variable Descriptor: Add Port Ingress Rule """
+    name = "Variable Descriptor: Add Port Ingress Rule"
+    fields_desc = [XByteField("branch", 0xD9),
+                   XShortField("leaf", 0x0502),
+                   XByteField("length", 0x80),
+                   XByteField("value", 0),
+                   ]
+
+
+class DeletePortIngressRule(Packet):
+    """ Variable Descriptor: Delete Port Ingress Rule """
+    name = "Variable Descriptor: Delete Port Ingress Rule"
+    fields_desc = [XByteField("branch", 0xD9),
+                   XShortField("leaf", 0x0503),
+                   XByteField("length", 1),
+                   XByteField("value", 0),
+                   ]
+
+####
+#### 0xd9 - BRANCH ATTRIBUTES
+####
+
+class EnableUserTraffic(Packet):
+    """ Variable Descriptor: Enable User Traffic """
+    name = "Variable Descriptor: Enable User Traffic"
+    fields_desc = [XByteField("branch", 0xD9),
+                   XShortField("leaf", 0x0601),
+                   XByteField("length", 1),
+                   XByteField("value", 0),
+                   ]
+
+class DisableUserTraffic(Packet):
+    """ Variable Descriptor: Disable User Traffic """
+    name = "Variable Descriptor: Disable User Traffic"
+    fields_desc = [XByteField("branch", 0xD9),
+                   XShortField("leaf", 0x0602)]
+
+class LoopbackEnable(Packet):
+    """ Variable Descriptor: Loopback Enable """
+    name = "Variable Descriptor: Loopback Enable"
+    fields_desc = [XByteField("branch", 0xD9),
+                   XShortField("leaf", 0x0603),
+                   XByteField("length", 1),
+                   XByteField("location", 0),
+                   ]
+
+class LoopbackDisable(Packet):
+    """ Variable Descriptor: Loopback Disable """
+    name = "Variable Descriptor: Loopback Disable"
+    fields_desc = [XByteField("branch", 0xD9),
+                   XShortField("leaf", 0x0604),
+                   XByteField("length", 1),
+                   XByteField("location", 0),
+                   ]
+
+class CurrentAlarmSummary(Packet):
+    """ Variable Descriptor: Current Alarm Summary """
+    name = "Variable Descriptor: Current Alarm Summary"
+    fields_desc = [XByteField("branch", 0xD9),
+                   XShortField("leaf", 0x0301)]
+
+
+##
+## Broadcom TLVs
+##
+class Broadcom07_7F_F1_Set01(Packet):
+    """ Variable Descriptor: Broadcom 0x07/0x7ff1 """
+    name = "Variable Descriptor: Broadcom 0x07/0x7ff1"
+    fields_desc = [XByteField("branch", 0x07),
+                   XShortField("leaf", 0x7ff1),
+                   XByteField("length", 2),
+                   XShortField("value0", 0x0101),
+                   ]
+
+class Broadcom07_7F_F1_Set02(Packet):
+    """ Variable Descriptor: Broadcom 0x07/0x7ff1 """
+    name = "Variable Descriptor: Broadcom 0x07/0x7ff1"
+    fields_desc = [XByteField("branch", 0x07),
+                   XShortField("leaf", 0x7ff1),
+                   XByteField("length", 7),
+                   XShortField("value0", 0x0201),
+                   XShortField("value1", 0x0000),
+                   XShortField("value2", 0x0107),
+                   XByteField("value3", 0xd0),
+                   ]
+
+class Broadcom07_7F_F1_Set03(Packet):
+    """ Variable Descriptor: Broadcom 0x07/0x7ff1 """
+    name = "Variable Descriptor: Broadcom 0x07/0x7ff1"
+    fields_desc = [XByteField("branch", 0x07),
+                   XShortField("leaf", 0x7ff1),
+                   XByteField("length", 7),
+                   XShortField("value0", 0x0301),
+                   XShortField("value1", 0x0000),
+                   XShortField("value2", 0x0100),
+                   XByteField("value3", 0xb8),
+                   ]
+
+class Broadcom07_7F_F1_Set04(Packet):
+    """ Variable Descriptor: Broadcom 0x07/0x7ff1 """
+    name = "Variable Descriptor: Broadcom 0x07/0x7ff1"
+    fields_desc = [XByteField("branch", 0x07),
+                   XShortField("leaf", 0x7ff1),
+                   XByteField("length", 1),
+                   XByteField("value0", 0x00),
+                   ]
+
+class Broadcom07_7F_F6_Set(Packet):
+    """ Variable Descriptor: Broadcom 0x07/0x7ff6 """
+    name = "Variable Descriptor: Broadcom 0x07/0x7ff6"
+    fields_desc = [XByteField("branch", 0x07),
+                   XShortField("leaf", 0x7ff6),
+                   XByteField("length", 2),
+                   XShortField("value0", 0x07d0),
+                   ]
+
+###
+### Clause 30 Attributes (0x07)
+###
+class Clause30AttributesMacEnable(Packet):
+    """ Variable Descriptor: Clause 30 Attributes MAC Enable """
+    name = "Variable Descriptor: Clause 30 Attributes MAC Enable"
+    fields_desc = [XByteField("branch", 0x07),
+                   XShortField("leaf", 0x001a),
+                   XByteField("length", 1),
+                   XByteField("value", 1),
+                   ]
+
+class EndOfPDU(Packet):
+    name = "End of EOAM PDU"
+    fields_desc = [BitEnumField("type", 0x00, 7, TLV_dictionary),
+                   BitField("length", 0x00, 9)]
diff --git a/voltha/adapters/tibit_onu/tibit_onu.py b/voltha/adapters/tibit_onu/tibit_onu.py
index 3ad3316..10b9d9c 100644
--- a/voltha/adapters/tibit_onu/tibit_onu.py
+++ b/voltha/adapters/tibit_onu/tibit_onu.py
@@ -18,18 +18,50 @@
 Tibit ONU device adapter
 """
 
+import json
+
+from uuid import uuid4
+
 import structlog
 from zope.interface import implementer
 
+from scapy.layers.inet import ICMP, IP
+from scapy.layers.l2 import Ether
+from twisted.internet.defer import DeferredQueue, inlineCallbacks
+from twisted.internet import reactor
+
+from voltha.core.logical_device_agent import mac_str_to_tuple
+
 from voltha.adapters.interface import IAdapterInterface
 from voltha.protos.adapter_pb2 import Adapter, AdapterConfig
+from voltha.protos.device_pb2 import Port
 from voltha.protos.device_pb2 import DeviceType, DeviceTypes
 from voltha.protos.health_pb2 import HealthStatus
-from voltha.protos.common_pb2 import LogLevel
+from voltha.protos.common_pb2 import LogLevel, ConnectStatus
 
+from voltha.protos.common_pb2 import OperStatus, AdminState
+
+from voltha.protos.logical_device_pb2 import LogicalDevice, LogicalPort
+from voltha.protos.openflow_13_pb2 import ofp_desc, ofp_port, OFPPF_10GB_FD, \
+    OFPPF_FIBER, OFPPS_LIVE, ofp_switch_features, OFPC_PORT_STATS, \
+    OFPC_GROUP_STATS, OFPC_TABLE_STATS, OFPC_FLOW_STATS
+
+from scapy.packet import Packet, bind_layers
+from scapy.fields import StrField
 
 log = structlog.get_logger()
 
+from EOAM_TLV import AddStaticMacAddress, DeleteStaticMacAddress
+from EOAM_TLV import ClearStaticMacTable
+from EOAM import EOAMPayload, EoamPayload, CablelabsOUI, DPoEOpcode_GetRequest
+
+
+# To be removed in favor of OAM
+class TBJSON(Packet):
+    """ TBJSON 'packet' layer. """
+    name = "TBJSON"
+    fields_desc = [StrField("data", default="")]
+
 
 @implementer(IAdapterInterface)
 class TibitOnuAdapter(object):
@@ -53,6 +85,7 @@
             version='0.1',
             config=AdapterConfig(log_level=LogLevel.INFO)
         )
+        self.incoming_messages = DeferredQueue()
 
     def start(self):
         log.debug('starting')
@@ -76,8 +109,92 @@
 
     def adopt_device(self, device):
         log.info('adopt-device', device=device)
+        reactor.callLater(0.1, self._onu_device_activation, device)
         return device
 
+    @inlineCallbacks
+    def _onu_device_activation(self, device):
+        # first we verify that we got parent reference and proxy info
+        assert device.parent_id
+        assert device.proxy_address.device_id
+        assert device.proxy_address.channel_id
+
+        # TODO: For now, pretend that we were able to contact the device and obtain
+        # additional information about it.  Should add real message.
+        device.vendor = 'Tibit Communications, Inc.'
+        device.model = '10G GPON ONU'
+        device.hardware_version = 'fa161020'
+        device.firmware_version = '16.10.01'
+        device.software_version = '1.0'
+        device.mac_address = '00:01:02:03:04:05'
+        device.serial_number = uuid4().hex
+        device.connect_status = ConnectStatus.REACHABLE
+        self.adapter_agent.update_device(device)
+
+        # then shortly after we create some ports for the device
+        uni_port = Port(
+            port_no=2,
+            label='UNI facing Ethernet port',
+            type=Port.ETHERNET_UNI,
+            admin_state=AdminState.ENABLED,
+            oper_status=OperStatus.ACTIVE
+        )
+        self.adapter_agent.add_port(device.id, uni_port)
+        self.adapter_agent.add_port(device.id, Port(
+            port_no=1,
+            label='PON port',
+            type=Port.PON_ONU,
+            admin_state=AdminState.ENABLED,
+            oper_status=OperStatus.ACTIVE,
+            peers=[
+                Port.PeerPort(
+                    device_id=device.parent_id,
+                    port_no=device.parent_port_no
+                )
+            ]
+        ))
+
+        # TODO adding vports to the logical device shall be done by agent?
+        # then we create the logical device port that corresponds to the UNI
+        # port of the device
+
+        # obtain logical device id
+        parent_device = self.adapter_agent.get_device(device.parent_id)
+        logical_device_id = parent_device.parent_id
+        assert logical_device_id
+
+        # we are going to use the proxy_address.channel_id as unique number
+        # and name for the virtual ports, as this is guaranteed to be unique
+        # in the context of the OLT port, so it is also unique in the context
+        # of the logical device
+        port_no = device.proxy_address.channel_id
+        cap = OFPPF_10GB_FD | OFPPF_FIBER
+        self.adapter_agent.add_logical_port(logical_device_id, LogicalPort(
+            id=str(port_no),
+            ofp_port=ofp_port(
+                port_no=port_no,
+                hw_addr=mac_str_to_tuple(device.mac_address),
+                name='uni-{}'.format(port_no),
+                config=0,
+                state=OFPPS_LIVE,
+                curr=cap,
+                advertised=cap,
+                peer=cap,
+                curr_speed=OFPPF_10GB_FD,
+                max_speed=OFPPF_10GB_FD
+            ),
+            device_id=device.id,
+            device_port_no=uni_port.port_no
+        ))
+
+        # simulate a proxied message sending and receving a reply
+        reply = yield self._message_exchange(device)
+
+        # and finally update to "ACTIVE"
+        device = self.adapter_agent.get_device(device.id)
+        device.oper_status = OperStatus.ACTIVE
+        self.adapter_agent.update_device(device)
+
     def abandon_device(self, device):
         raise NotImplementedError(0
                                   )
@@ -95,5 +212,35 @@
         raise NotImplementedError()
 
     def receive_proxied_message(self, proxy_address, msg):
-        log.debug('send-proxied-message',
+        log.debug('receive-proxied-message',
                   proxy_address=proxy_address, msg=msg)
+        self.incoming_messages.put(msg)
+
+    @inlineCallbacks
+    def _message_exchange(self, device):
+
+        # register for receiving async messages
+        self.adapter_agent.register_for_proxied_messages(device.proxy_address)
+
+        # reset incoming message queue
+        while self.incoming_messages.pending:
+            _ = yield self.incoming_messages.get()
+
+        # construct message
+        msg = EoamPayload(body=CablelabsOUI() /
+                               DPoEOpcode_GetRequest() /
+                               # MAC address for 230.10.10.10
+                               AddStaticMacAddress(mac='01:00:5e:0a:0a:0a') # device.mac_address)
+                          )
+
+        # send message
+        log.info('ONU-send-proxied-message-%s' % msg)
+        self.adapter_agent.send_proxied_message(device.proxy_address, msg)
+
+        log.info('ONU-log incoming messages BEFORE')
+        # wait till we detect incoming message
+        yield self.incoming_messages.get()
+        log.info('ONU-log incoming messages AFTER')
+
+        # by returning we allow the device to be shown as active, which
+        # indirectly verified that message passing works
diff --git a/voltha/core/device_agent.py b/voltha/core/device_agent.py
index acd5bc8..2667176 100644
--- a/voltha/core/device_agent.py
+++ b/voltha/core/device_agent.py
@@ -136,11 +136,9 @@
     def _activate_device(self, device, dry_run=False):
         self.log.info('activate-device', device=device, dry_run=dry_run)
         if not dry_run:
-            device = yield self.adapter_agent.adopt_device(device)
             device.oper_status = OperStatus.ACTIVATING
-            # successful return from this may also populated the device
-            # data, so we need to write it back
-            reactor.callLater(0, self.update_device, device)
+            self.update_device(device)
+            yield self.adapter_agent.adopt_device(device)
 
     def update_device(self, device):
         self.last_data = device  # so that we don't propagate back
diff --git a/voltha/core/logical_device_agent.py b/voltha/core/logical_device_agent.py
index 998f85b..ec06379 100644
--- a/voltha/core/logical_device_agent.py
+++ b/voltha/core/logical_device_agent.py
@@ -69,6 +69,10 @@
 
         self._routes = None
 
+        self.log = structlog.get_logger(logical_device_id=logical_device.id)
+
+        self.log = structlog.get_logger(logical_device_id=logical_device.id)
+
     def start(self):
         self.log.debug('starting')
         self.log.info('started')
diff --git a/voltha/protos/device.proto b/voltha/protos/device.proto
index b3b1711..20eec6d 100644
--- a/voltha/protos/device.proto
+++ b/voltha/protos/device.proto
@@ -110,9 +110,10 @@
         // ("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx")
         string ipv6_address = 15;
 
-        ProxyAddress proxy_address = 19;
     };
 
+    ProxyAddress proxy_address = 19;
+
     AdminState.AdminState admin_state = 16;
 
     OperStatus.OperStatus oper_status = 17 [(access) = READ_ONLY];