VOL-2823 Change vlan-filter task to support TT case

-Instead of hardcoded values, use the vid and pcp values in flow.
-Add task removal for flow-remove case.
-make incremental EVTO feature configurable 'accept_incremental_evto_update'
 parameter. This feature is disabled by default.

Change-Id: Id6178af89daa0b6897274db6067025d271fdd101
diff --git a/python/adapters/brcm_openomci_onu/brcm_openomci_onu_handler.py b/python/adapters/brcm_openomci_onu/brcm_openomci_onu_handler.py
index 700a0ee..9c8ebfa 100644
--- a/python/adapters/brcm_openomci_onu/brcm_openomci_onu_handler.py
+++ b/python/adapters/brcm_openomci_onu/brcm_openomci_onu_handler.py
@@ -502,7 +502,6 @@
                                       _set_vlan_pcp=filter_info.get("set_vlan_pcp"),
                                       tp_id=filter_info.get("tp_id"))
                     # Now remove the entry from the dictionary
-                    self._queued_vlan_filter_task[uni_id][tp_id].remove(filter_info)
                     self.log.debug("executed-queued-vlan-filter-task",
                                    uni_id=uni_id, tp_id=tp_id)
                 # Now delete the key entries once we have handled the queued vlan filter tasks.
@@ -847,7 +846,18 @@
                             self.log.debug('The dhcp trap-to-host flow will be discarded', device_id=device.id)
                             return
 
-                        _vlan_vid = 0
+                        _match_vlan_vid = None
+                        for field in fd.get_ofb_fields(flow):
+                            if field.type == fd.VLAN_VID:
+                                if field.vlan_vid == RESERVED_TRANSPARENT_VLAN and field.vlan_vid_mask == RESERVED_TRANSPARENT_VLAN:
+                                    _match_vlan_vid = RESERVED_TRANSPARENT_VLAN
+                                else:
+                                    _match_vlan_vid = field.vlan_vid & 0xfff
+                                self.log.debug('field-type-vlan-vid',
+                                               vlan=_match_vlan_vid)
+
+                        _set_vlan_vid = None
+                        _set_vlan_pcp = None
                         # Retrieve the VLAN_VID that needs to be removed from the EVTO rule on the ONU.
                         for action in fd.get_actions(flow):
                             if action.type == fd.SET_FIELD:
@@ -855,9 +865,13 @@
                                 assert (action.set_field.field.oxm_class ==
                                         OFPXMC_OPENFLOW_BASIC)
                                 if _field.type == fd.VLAN_VID:
-                                    _vlan_vid = _field.vlan_vid & 0xfff
+                                    _set_vlan_vid = _field.vlan_vid & 0xfff
                                     self.log.debug('vlan-vid-to-remove',
-                                                   _vlan_vid=_vlan_vid, in_port=_in_port)
+                                                   _vlan_vid=_set_vlan_vid, in_port=_in_port)
+                                elif _field.type == fd.VLAN_PCP:
+                                    _set_vlan_pcp = _field.vlan_pcp
+                                    self.log.debug('set-field-type-vlan-pcp',
+                                                   vlan_pcp=_set_vlan_pcp)
 
                         uni_port = self.uni_port(_in_port)
                         uni_id = _in_port & 0xF
@@ -870,7 +884,8 @@
                     # The vlan filter remove should be followed by a TP deleted for that TP ID.
                     # Use this information to re-schedule any vlan filter add tasks for the same TP ID again.
                     # First check if the TP download was done, before we access that TP delete is necessary
-                    if uni_id in self._tech_profile_download_done and tp_id in self._tech_profile_download_done[uni_id] and \
+                    if uni_id in self._tech_profile_download_done and tp_id in self._tech_profile_download_done[
+                        uni_id] and \
                             self._tech_profile_download_done[uni_id][tp_id] is True:
                         if uni_id not in self._pending_delete_tp:
                             self._pending_delete_tp[uni_id] = dict()
@@ -878,9 +893,11 @@
                         else:
                             self._pending_delete_tp[uni_id][tp_id] = True
                     # Deleting flow from ONU.
-                    self._remove_vlan_filter_task(device, uni_id, uni_port=uni_port, _set_vlan_vid=_vlan_vid,
-                                                  match_vlan=_vlan_vid, tp_id=tp_id)
-
+                    self._remove_vlan_filter_task(device, uni_id, uni_port=uni_port,
+                                                  _set_vlan_pcp=_set_vlan_pcp,
+                                                  _set_vlan_vid=_set_vlan_vid,
+                                                  match_vlan=_match_vlan_vid,
+                                                  tp_id=tp_id)
                     # TODO:Delete TD task.
                 except Exception as e:
                     self.log.exception('failed-to-remove-flow', e=e)
@@ -916,7 +933,7 @@
                 _push_tpid = None
                 _field = None
                 _set_vlan_vid = None
-                _set_vlan_pcp = 0
+                _set_vlan_pcp = None
                 _tunnel_id = None
                 self.log.debug("add-flow", device_id=device.id, flow=flow)
 
@@ -1385,7 +1402,7 @@
                 self._onu_persisted_state['onu_id'] = onu_indication.onu_id
                 self._onu_persisted_state['intf_id'] = onu_indication.intf_id
                 self._onu_persisted_state['admin_state'] = onu_indication.admin_state
-                self._onu_persisted_state['oper_state'] =  onu_indication.oper_state
+                self._onu_persisted_state['oper_state'] = onu_indication.oper_state
 
                 if onu_indication.oper_state == "up":
                     yield self.create_interface(onu_indication)
@@ -1471,7 +1488,6 @@
             self.log.warn('received-onu-indication-for-active-onu', onu_indication=onu_indication)
             return
 
-
         yield self.core_proxy.device_state_update(self.device_id, oper_status=OperStatus.ACTIVATING,
                                                   connect_status=ConnectStatus.REACHABLE)
 
diff --git a/python/adapters/brcm_openomci_onu/main.py b/python/adapters/brcm_openomci_onu/main.py
index 54161ec..def8e64 100755
--- a/python/adapters/brcm_openomci_onu/main.py
+++ b/python/adapters/brcm_openomci_onu/main.py
@@ -64,6 +64,7 @@
     device_type=os.environ.get('DEVICE_TYPE', 'openonu'),
     accept_bulk_flow=os.environ.get('ACCEPT_BULK_FLOW', True),
     accept_atomic_flow=os.environ.get('ACCEPT_ATOMIC_FLOW', True),
+    accept_incremental_evto_update=os.environ.get('ACCEPT_INCREMENTAL_EVTO_UPDATE', False),
     etcd=os.environ.get('ETCD', 'localhost:2379'),
     core_topic=os.environ.get('CORE_TOPIC', 'rwcore'),
     event_topic=os.environ.get('EVENT_TOPIC', 'voltha.events'),
@@ -148,6 +149,14 @@
                         default=defs['accept_atomic_flow'],
                         help=_help)
 
+    _help = 'specifies whether the adapter accepts incremental EVTO updates ' \
+            '(default: %s)' % defs['accept_incremental_evto_update']
+    parser.add_argument('-aie', '--accept_incremental_evto_update',
+                        dest='accept_incremental_evto_update',
+                        action='store',
+                        default=defs['accept_incremental_evto_update'],
+                        help=_help)
+
     _help = '<hostname>:<port> to etcd server (default: %s)' % defs['etcd']
     parser.add_argument('-e', '--etcd',
                         dest='etcd',
diff --git a/python/adapters/brcm_openomci_onu/omci/brcm_mib_download_task.py b/python/adapters/brcm_openomci_onu/omci/brcm_mib_download_task.py
index 678fd54..1e8003c 100644
--- a/python/adapters/brcm_openomci_onu/omci/brcm_mib_download_task.py
+++ b/python/adapters/brcm_openomci_onu/omci/brcm_mib_download_task.py
@@ -17,7 +17,7 @@
 from twisted.internet.defer import inlineCallbacks, returnValue, TimeoutError, failure
 from pyvoltha.adapters.extensions.omci.omci_me import PptpEthernetUniFrame, GalEthernetProfileFrame, \
     MacBridgePortConfigurationDataFrame, MacBridgeServiceProfileFrame, Ieee8021pMapperServiceProfileFrame, \
-    VeipUniFrame, ExtendedVlanTaggingOperationConfigurationDataFrame
+    VeipUniFrame, ExtendedVlanTaggingOperationConfigurationDataFrame,Ont2GFrame
 from pyvoltha.adapters.extensions.omci.tasks.task import Task
 from pyvoltha.adapters.extensions.omci.omci_defs import EntityOperations, ReasonCodes
 from uni_port import UniType
@@ -195,6 +195,13 @@
             results = yield omci_cc.send(frame)
             self.check_status_and_state(results, 'create-gal-ethernet-profile')
 
+            ont2_attributes = dict(current_connectivity_mode=5)
+            msg = Ont2GFrame(attributes=ont2_attributes)
+            frame = msg.set()
+            self.log.debug('openomci-msg', omci_msg=msg)
+            results = yield omci_cc.send(frame)
+            self.check_status_and_state(results, 'set-ont2g')
+
         except TimeoutError as e:
             self.log.warn('rx-timeout-initial-gal-profile', e=e)
             raise
@@ -223,12 +230,12 @@
             # TODO: magic. event if static, assign to a meaningful variable name
             attributes = {
                 'spanning_tree_ind': False,
-                'learning_ind': True,
+                'learning_ind': False,
                 'priority': 0x8000,
                 'max_age': 20 * 256,
                 'hello_time': 2 * 256,
                 'forward_delay': 15 * 256,
-                'unknown_mac_address_discard': True
+                'unknown_mac_address_discard': False
             }
             msg = MacBridgeServiceProfileFrame(
                 self._mac_bridge_service_profile_entity_id + uni_port.mac_bridge_port_num,
@@ -253,10 +260,10 @@
 
             # default to PPTP
             tp_type = 1
+            association_type = 2
             if uni_port.type.value == UniType.VEIP.value:
                 tp_type = 11
-            elif uni_port.type.value == UniType.PPTP.value:
-                tp_type = 1
+                association_type = 10
 
             msg = MacBridgePortConfigurationDataFrame(
                 self._mac_bridge_port_ani_entity_id + uni_port.entity_id,  # Entity ID
@@ -270,6 +277,40 @@
             results = yield omci_cc.send(frame)
             self.check_status_and_state(results, 'create-mac-bridge-port-configuration-data-uni-port')
 
+
+            ################################################################################
+            # Create Extended VLAN Tagging Operation config (UNI-side)
+            #
+            #  EntityID relates to the VLAN TCIS later used int vlan filter task.  This only
+            #  sets up the inital MIB entry as it relates to port config, it does not set vlan
+            #  that is saved for the vlan filter task
+            #
+            #  References:
+            #            - PPTP Ethernet or VEIP UNI
+            #
+
+            attributes = dict(
+                association_type=association_type,             # Assoc Type, PPTP/VEIP Ethernet UNI
+                associated_me_pointer=uni_port.entity_id,      # Assoc ME, PPTP/VEIP Entity Id
+
+                # See VOL-1311 - Need to set table during create to avoid exception
+                # trying to read back table during post-create-read-missing-attributes
+                # But, because this is a R/W attribute. Some ONU may not accept the
+                # value during create. It is repeated again in a set below.
+                input_tpid=self._input_tpid,    # input TPID
+                output_tpid=self._output_tpid,  # output TPID
+            )
+
+            msg = ExtendedVlanTaggingOperationConfigurationDataFrame(
+                self._mac_bridge_service_profile_entity_id + uni_port.mac_bridge_port_num,  # Bridge Entity ID
+                attributes=attributes
+            )
+
+            frame = msg.create()
+            self.log.debug('openomci-msg', omci_msg=msg)
+            results = yield omci_cc.send(frame)
+            self.check_status_and_state(results, 'create-extended-vlan-tagging-operation-configuration-data')
+
         except TimeoutError as e:
             self.log.warn('rx-timeout-inital-per-uni-setup', e=e)
             raise
diff --git a/python/adapters/brcm_openomci_onu/omci/brcm_vlan_filter_task.py b/python/adapters/brcm_openomci_onu/omci/brcm_vlan_filter_task.py
index 484ed45..83a517f 100644
--- a/python/adapters/brcm_openomci_onu/omci/brcm_vlan_filter_task.py
+++ b/python/adapters/brcm_openomci_onu/omci/brcm_vlan_filter_task.py
@@ -20,8 +20,10 @@
 from twisted.internet import reactor
 from twisted.internet.defer import inlineCallbacks, failure, returnValue
 from pyvoltha.adapters.extensions.omci.omci_defs import ReasonCodes, EntityOperations
+from pyvoltha.adapters.extensions.omci.omci_entities import VlanTaggingFilterData
 from pyvoltha.adapters.extensions.omci.omci_me import \
-    VlanTaggingOperation, VlanTaggingFilterDataFrame, ExtendedVlanTaggingOperationConfigurationDataFrame
+    VlanTaggingOperation, VlanTaggingFilterDataFrame, ExtendedVlanTaggingOperationConfigurationDataFrame, \
+    ExtendedVlanTaggingOperationConfigurationData
 from uni_port import UniType
 from uni_port import RESERVED_TRANSPARENT_VLAN
 from pon_port import DEFAULT_TPID
@@ -51,6 +53,7 @@
         :param handler: (BrcmOpenomciOnuHandler) ONU Device Handler Instance
         :param uni_port: (UniPort) Object instance representing the uni port and its settings
         :param set_vlan_id: (int) VLAN to filter for and set
+        :param add_tag: (bool) Flag to identify VLAN Tagging or Untagging
         :param tp_id: (int) TP ID for the flow
         :param priority: (int) OpenOMCI Task priority (0..255) 255 is the highest
         """
@@ -68,17 +71,40 @@
                                         uni_port=uni_port.port_number,
                                         set_vlan_id=set_vlan_id)
 
+        self._onu_handler = handler
         self._device = omci_agent.get_device(handler.device_id)
         self._uni_port = uni_port
         self._set_vlan_id = set_vlan_id
-        self._set_vlan_pcp = set_vlan_pcp
-        self._match_vlan = match_vlan
+
+        # If not setting any pbit, copy the pbit from the received vlan tag
+        if set_vlan_pcp is None:
+            self._set_vlan_pcp = 8  # Copy from the inner priority of the received frame
+        else:
+            self._set_vlan_pcp = set_vlan_pcp
+
+        # If not matching on any vlan do not filter for vlan value.  effectively match on untagged
+        if match_vlan is None:
+            self._match_vlan = RESERVED_TRANSPARENT_VLAN  # Do not filter on the VID
+        else:
+            self._match_vlan = match_vlan
+
+        self._vlan_pcp = 8  # Do not filter on priority
+
+        # If the tag is not transparent then need to remove it.
+        self._treatment_tags_to_remove = 1
+        if self._match_vlan == RESERVED_TRANSPARENT_VLAN:  # Do not filter on the VID
+            self._vlan_pcp = 15  # This entry is a no-tag rule; ignore all other VLAN tag filter fields
+            self._treatment_tags_to_remove = 0
+
+        # If matching on untagged and trying to copy pbit from non-existent received vlan, set pbit to zero
+        if self._match_vlan == RESERVED_TRANSPARENT_VLAN and self._set_vlan_pcp == 8:
+            self._set_vlan_pcp = 0
+
         self._add_tag = add_tag
         self._tp_id = tp_id
         self._results = None
         self._local_deferred = None
         self._config = self._device.configuration
-
         self._input_tpid = DEFAULT_TPID
         self._output_tpid = DEFAULT_TPID
 
@@ -113,223 +139,24 @@
         """
         Perform the vlan tagging
         """
-        self.log.debug('vlan-filter-tagging-task', device_id=self._device._device_id, uni_port=self._uni_port, set_vlan_id=self._set_vlan_id, \
-            set_vlan_pcp=self._set_vlan_pcp, match_vlan=self._match_vlan, tp_id=self._tp_id, add_tag=self._add_tag)
-
+        self.log.debug('vlan-filter-tagging-task', uni_port=self._uni_port, set_vlan_id=self._set_vlan_id,
+                       set_vlan_pcp=self._set_vlan_pcp, match_vlan=self._match_vlan, tp_id=self._tp_id,
+                       add_tag=self._add_tag)
         try:
             if self._add_tag:
-                ################################################################################
-                # VLAN Tagging Filter config
-                #
-                #  EntityID will be referenced by:
-                #            - Nothing
-                #  References:
-                #            - MacBridgePortConfigurationData for the ANI/PON side
-                #
-
-
-                # Delete bridge ani side vlan filter
-                eid = self._mac_bridge_port_ani_entity_id + self._uni_port.entity_id + self._tp_id  # Entity ID
-                msg = VlanTaggingFilterDataFrame(eid)
-                frame = msg.delete()
-                self.log.debug('openomci-msg', omci_msg=msg)
-                self.strobe_watchdog()
-                results = yield self._device.omci_cc.send(frame)
-                self.check_status_and_state(results, 'flow-delete-vlan-tagging-filter-data')
-
-                ################################################################################
-                # Create Extended VLAN Tagging Operation config (UNI-side)
-                #
-                #  EntityID relates to the VLAN TCIS later used int vlan filter task.  This only
-                #  sets up the inital MIB entry as it relates to port config, it does not set vlan
-                #  that is saved for the vlan filter task
-                #
-                #  References:
-                #            - PPTP Ethernet or VEIP UNI
-                #
-
-
-                # Delete uni side evto
-                msg = ExtendedVlanTaggingOperationConfigurationDataFrame(
-                    self._mac_bridge_service_profile_entity_id + self._uni_port.mac_bridge_port_num,
-                )
-                frame = msg.delete()
-                self.log.debug('openomci-msg', omci_msg=msg)
-                results = yield self._device.omci_cc.send(frame)
-                self.check_status_and_state(results, 'delete-extended-vlan-tagging-operation-configuration-data')
-
-
-                # Re-Create uni side evto
-                # default to PPTP
-                association_type = 2
-                if self._uni_port.type.value == UniType.VEIP.value:
-                    association_type = 10
-                elif self._uni_port.type.value == UniType.PPTP.value:
-                    association_type = 2
-
-                attributes = dict(
-                    association_type=association_type,             # Assoc Type, PPTP/VEIP Ethernet UNI
-                    associated_me_pointer=self._uni_port.entity_id,      # Assoc ME, PPTP/VEIP Entity Id
-
-                    # See VOL-1311 - Need to set table during create to avoid exception
-                    # trying to read back table during post-create-read-missing-attributes
-                    # But, because this is a R/W attribute. Some ONU may not accept the
-                    # value during create. It is repeated again in a set below.
-                    input_tpid=self._input_tpid,    # input TPID
-                    output_tpid=self._output_tpid,  # output TPID
-                )
-
-                msg = ExtendedVlanTaggingOperationConfigurationDataFrame(
-                    self._mac_bridge_service_profile_entity_id + self._uni_port.mac_bridge_port_num,  # Bridge Entity ID
-                    attributes=attributes
-                )
-
-                frame = msg.create()
-                self.log.debug('openomci-msg', omci_msg=msg)
-                results = yield self._device.omci_cc.send(frame)
-                self.check_status_and_state(results, 'create-extended-vlan-tagging-operation-configuration-data')
-
-                attributes = dict(
-                    # Specifies the TPIDs in use and that operations in the downstream direction are
-                    # inverse to the operations in the upstream direction
-                    input_tpid=self._input_tpid,    # input TPID
-                    output_tpid=self._output_tpid,  # output TPID
-                    downstream_mode=0,              # inverse of upstream
-                )
-
-                msg = ExtendedVlanTaggingOperationConfigurationDataFrame(
-                    self._mac_bridge_service_profile_entity_id + self._uni_port.mac_bridge_port_num,  # Bridge Entity ID
-                    attributes=attributes
-                )
-
-                frame = msg.set()
-                self.log.debug('openomci-msg', omci_msg=msg)
-                self.strobe_watchdog()
-                results = yield self._device.omci_cc.send(frame)
-                self.check_status_and_state(results, 'set-extended-vlan-tagging-operation-configuration-data')
-
-                # Onu-Transparent
-                if self._set_vlan_id == RESERVED_TRANSPARENT_VLAN:
-                    # Transparently send any single tagged packet.
-                    # As the onu is to be transparent, no need to create VlanTaggingFilterData ME.
-                    # Any other specific rules will take priority over this, so not setting any other vlan specific rules
-                    attributes = dict(
-                        received_frame_vlan_tagging_operation_table=
-                        VlanTaggingOperation(
-                            filter_outer_priority=15,
-                            filter_outer_vid=4096,
-                            filter_outer_tpid_de=0,
-                            filter_inner_priority=14,
-                            filter_inner_vid=4096,
-                            filter_inner_tpid_de=0,
-                            filter_ether_type=0,
-                            treatment_tags_to_remove=0,
-                            treatment_outer_priority=15,
-                            treatment_outer_vid=0,
-                            treatment_outer_tpid_de=0,
-                            treatment_inner_priority=15,
-                            treatment_inner_vid=0,
-                            treatment_inner_tpid_de=4
-                        )
-                    )
-
-                    msg = ExtendedVlanTaggingOperationConfigurationDataFrame(
-                        self._mac_bridge_service_profile_entity_id + self._uni_port.mac_bridge_port_num,  # Bridge Entity ID
-                        attributes=attributes
-                    )
-
-                    frame = msg.set()
-                    self.log.debug('openomci-msg', omci_msg=msg)
-                    self.strobe_watchdog()
-                    results = yield self._device.omci_cc.send(frame)
-                    self.check_status_and_state(results, 'set-evto-table-transparent-vlan')
-
+                if not self._onu_handler.args.accept_incremental_evto_update:
+                    yield self._bulk_update_evto_and_vlan_tag_filter()
                 else:
-                    # Re-Create bridge ani side vlan filter
-                    forward_operation = 0x10  # VID investigation
-
-                    msg = VlanTaggingFilterDataFrame(
-                        eid,
-                        vlan_tcis=[self._set_vlan_id],  # VLAN IDs
-                        forward_operation=forward_operation
-                    )
-                    frame = msg.create()
-                    self.log.debug('openomci-msg', omci_msg=msg)
-                    self.strobe_watchdog()
-                    results = yield self._device.omci_cc.send(frame)
-                    self.check_status_and_state(results, 'flow-create-vlan-tagging-filter-data')
-                    # Update uni side extended vlan filter
-                    # filter for untagged
-                    attributes = dict(
-                        received_frame_vlan_tagging_operation_table=
-                        VlanTaggingOperation(
-                            filter_outer_priority=15,
-                            filter_outer_vid=4096,
-                            filter_outer_tpid_de=0,
-                            filter_inner_priority=15,
-                            filter_inner_vid=4096,
-                            filter_inner_tpid_de=0,
-                            filter_ether_type=0,
-                            treatment_tags_to_remove=0,
-                            treatment_outer_priority=15,
-                            treatment_outer_vid=0,
-                            treatment_outer_tpid_de=0,
-                            treatment_inner_priority=0,
-                            treatment_inner_vid=self._set_vlan_id,
-                            treatment_inner_tpid_de=4
-                        )
-                    )
-
-                    msg = ExtendedVlanTaggingOperationConfigurationDataFrame(
-                        self._mac_bridge_service_profile_entity_id + self._uni_port.mac_bridge_port_num,  # Bridge Entity ID
-                        attributes=attributes
-                    )
-
-                    frame = msg.set()
-                    self.log.debug('openomci-msg', omci_msg=msg)
-                    self.strobe_watchdog()
-                    results = yield self._device.omci_cc.send(frame)
-                    self.check_status_and_state(results, 'set-evto-table-untagged')
-
-                    # Update uni side extended vlan filter
-                    # filter for vlan 0
-                    attributes = dict(
-                        received_frame_vlan_tagging_operation_table=
-                        VlanTaggingOperation(
-                            filter_outer_priority=15,  # This entry is not a double-tag rule
-                            filter_outer_vid=4096,  # Do not filter on the outer VID value
-                            filter_outer_tpid_de=0,  # Do not filter on the outer TPID field
-
-                            filter_inner_priority=8,  # Filter on inner vlan
-                            filter_inner_vid=0x0,  # Look for vlan 0
-                            filter_inner_tpid_de=0,  # Do not filter on inner TPID field
-                            filter_ether_type=0,  # Do not filter on EtherType
-
-                            treatment_tags_to_remove=1,
-                            treatment_outer_priority=15,
-                            treatment_outer_vid=0,
-                            treatment_outer_tpid_de=0,
-
-                            treatment_inner_priority=8,  # Add an inner tag and insert this value as the priority
-                            treatment_inner_vid=self._set_vlan_id,  # use this value as the VID in the inner VLAN tag
-                            treatment_inner_tpid_de=4,  # set TPID
-                        )
-                    )
-                    msg = ExtendedVlanTaggingOperationConfigurationDataFrame(
-                        self._mac_bridge_service_profile_entity_id + self._uni_port.mac_bridge_port_num,  # Bridge Entity ID
-                        attributes=attributes  # See above
-                    )
-                    frame = msg.set()
-                    self.log.debug('openomci-msg', omci_msg=msg)
-                    self.strobe_watchdog()
-                    results = yield self._device.omci_cc.send(frame)
-                    self.check_status_and_state(results, 'set-evto-table-zero-tagged')
-
-            else: #addTag = False
-                #TODO: needs to be implemented - future task.
-                self.log.debug('removing-vlan-filter-tag', uni_port=self._uni_port, match_vlan=self._match_vlan, )
+                    yield self._incremental_update_evto_and_vlan_tag_filter()
+            else:  # addTag = False
+                if self._onu_handler.args.accept_incremental_evto_update:
+                    self.log.info('removing-vlan-tagging')
+                    yield self._delete_service_flow()
+                    yield self._delete_vlan_filter_entity()
+                else:
+                    # Will be reset anyway on new vlan tagging operation
+                    self.log.info("not-removing-vlan-tagging")
             self.deferred.callback(self)
-
         except Exception as e:
             self.log.exception('setting-vlan-tagging', e=e)
             self.deferred.errback(failure.Failure(e))
@@ -361,3 +188,411 @@
         elif status == RC.InstanceExists:
             return False
 
+    @inlineCallbacks
+    def _delete_service_flow(self):
+        extended_vlan_tagging_entity_id = self._mac_bridge_service_profile_entity_id + \
+                                          self._uni_port.mac_bridge_port_num
+
+        # See G.988 regarding evto row deletes for "default" flows:
+        #
+        # As an exception to the rule on ordered processing, these default rules are always
+        # considered as a last resort for frames that do not match any other rule. Best
+        # practice dictates that these entries not be deleted by the OLT; however, they
+        # can be modified to produce the desired default behaviour.
+        #
+        # 15, 4096, x, 15, 4096, x, 0, (0, 15, x, x, 15, x, x) – no tags
+        # 15, 4096, x, 14, 4096, x, 0, (0, 15, x, x, 15, x, x) – 1 tag
+        # 14, 4096, x, 14, 4096, x, 0, (0, 15, x, x, 15, x, x) – 2 tags
+
+        # outer_prio is 15, outer vid is 4096  inner prio is 15, inner vid is 4096
+        # its a default rule... dont delete it.
+        if self._match_vlan == RESERVED_TRANSPARENT_VLAN and self._vlan_pcp == 15:
+            self.log.warn("should-not-delete-onu-builtin-no-tag-flow")
+            return
+
+        # outer_prio is 15, outer vid is 4096  inner prio is 14, inner vid is 4096
+        # its a default rule... dont delete it.
+        if self._match_vlan == RESERVED_TRANSPARENT_VLAN and self._vlan_pcp == 14:
+            self.log.warn("should-not-delete-onu-builtin-single-tag-flow")
+            return
+
+        entry = VlanTaggingOperation(
+            filter_outer_priority=15,
+            filter_outer_vid=4096,
+            filter_outer_tpid_de=0,
+
+            filter_inner_priority=self._vlan_pcp,
+            filter_inner_vid=self._match_vlan,
+            filter_inner_tpid_de=0,
+            filter_ether_type=0
+        )
+        # delete this entry using the filter rules as the key.
+        # this function automatically fills 0xFF in the last 8 treatment bytes
+        entry = entry.delete()
+        attributes = dict(received_frame_vlan_tagging_operation_table=entry)
+
+        msg = ExtendedVlanTaggingOperationConfigurationDataFrame(
+            extended_vlan_tagging_entity_id,  # Bridge Entity ID
+            attributes=attributes  # See above
+        )
+        frame = msg.set()
+        self.log.debug('openomci-msg', omci_msg=msg)
+        results = yield self._device.omci_cc.send(frame)
+        self.check_status_and_state(results, 'delete-service-flow')
+
+    @inlineCallbacks
+    def _delete_vlan_filter_entity(self):
+        vlan_tagging_entity_id = int(self._mac_bridge_port_ani_entity_id + self._uni_port.entity_id
+                                     + self._tp_id)
+        self.log.debug("Vlan tagging filter data frame will be deleted.",
+                       expected_me_id=vlan_tagging_entity_id)
+        msg = VlanTaggingFilterDataFrame(vlan_tagging_entity_id)
+        frame = msg.delete()
+        self.log.debug('openomci-msg', omci_msg=msg)
+        results = yield self._device.omci_cc.send(frame)
+        self.check_status_and_state(results, 'flow-delete-vlan-tagging-filter-data')
+
+    @inlineCallbacks
+    def _create_vlan_filter_entity(self, vlan_tagging_entity_id):
+
+        self.log.debug("Vlan tagging filter data frame will be created.",
+                       expected_me_id=vlan_tagging_entity_id)
+        vlan_tagging_me = self._device.query_mib(VlanTaggingFilterData.class_id,
+                                                 instance_id=int(vlan_tagging_entity_id))
+        if len(vlan_tagging_me) == 0:
+            forward_operation = 0x10  # VID investigation
+            self.log.debug("vlan id isn't reserved")
+            self.log.debug("forward_operation", forward_operation=forward_operation)
+            self.log.debug("set_vlan_id", vlan_id=self._set_vlan_id)
+            # When the PUSH VLAN is RESERVED_VLAN (4095), let ONU be transparent
+            if self._set_vlan_id == RESERVED_TRANSPARENT_VLAN:
+                forward_operation = 0x00  # no investigation, ONU transparent
+
+            # Create bridge ani side vlan filter
+            msg = VlanTaggingFilterDataFrame(
+                int(vlan_tagging_entity_id),  # Entity ID
+                vlan_tcis=[self._set_vlan_id],  # VLAN IDs
+                forward_operation=forward_operation
+            )
+
+            self.log.debug("created vlan tagging data frame msg")
+            frame = msg.create()
+            self.log.debug('openomci-msg', omci_msg=msg)
+            results = yield self._device.omci_cc.send(frame)
+            self.check_status_and_state(results, 'create-vlan-tagging-filter-data')
+
+    @inlineCallbacks
+    def _reset_evto_and_vlan_tag_filter(self):
+        self.log.info("resetting-evto-and-vlan-tag-filter")
+        # Delete bridge ani side vlan filter
+        eid = self._mac_bridge_port_ani_entity_id + self._uni_port.entity_id + self._tp_id  # Entity ID
+        msg = VlanTaggingFilterDataFrame(eid)
+        frame = msg.delete()
+        self.log.debug('openomci-msg', omci_msg=msg)
+        self.strobe_watchdog()
+        results = yield self._device.omci_cc.send(frame)
+        self.check_status_and_state(results, 'flow-delete-vlan-tagging-filter-data')
+
+        ################################################################################
+        # Create Extended VLAN Tagging Operation config (UNI-side)
+        #
+        #  EntityID relates to the VLAN TCIS later used int vlan filter task.  This only
+        #  sets up the inital MIB entry as it relates to port config, it does not set vlan
+        #  that is saved for the vlan filter task
+        #
+        #  References:
+        #            - PPTP Ethernet or VEIP UNI
+        #
+
+        # Delete uni side evto
+        msg = ExtendedVlanTaggingOperationConfigurationDataFrame(
+            self._mac_bridge_service_profile_entity_id + self._uni_port.mac_bridge_port_num,
+        )
+        frame = msg.delete()
+        self.log.debug('openomci-msg', omci_msg=msg)
+        results = yield self._device.omci_cc.send(frame)
+        self.check_status_and_state(results, 'delete-extended-vlan-tagging-operation-configuration-data')
+
+        # Re-Create uni side evto
+        # default to PPTP
+        association_type = 2
+        if self._uni_port.type.value == UniType.VEIP.value:
+            association_type = 10
+        elif self._uni_port.type.value == UniType.PPTP.value:
+            association_type = 2
+
+        attributes = dict(
+            association_type=association_type,  # Assoc Type, PPTP/VEIP Ethernet UNI
+            associated_me_pointer=self._uni_port.entity_id,  # Assoc ME, PPTP/VEIP Entity Id
+
+            # See VOL-1311 - Need to set table during create to avoid exception
+            # trying to read back table during post-create-read-missing-attributes
+            # But, because this is a R/W attribute. Some ONU may not accept the
+            # value during create. It is repeated again in a set below.
+            input_tpid=self._input_tpid,  # input TPID
+            output_tpid=self._output_tpid,  # output TPID
+        )
+
+        msg = ExtendedVlanTaggingOperationConfigurationDataFrame(
+            self._mac_bridge_service_profile_entity_id + self._uni_port.mac_bridge_port_num,  # Bridge Entity ID
+            attributes=attributes
+        )
+
+        frame = msg.create()
+        self.log.debug('openomci-msg', omci_msg=msg)
+        results = yield self._device.omci_cc.send(frame)
+        self.check_status_and_state(results, 'create-extended-vlan-tagging-operation-configuration-data')
+
+    @inlineCallbacks
+    def _incremental_update_evto_and_vlan_tag_filter(self):
+        self.log.info("incremental-update-evto-and-vlan-tag-filter")
+        vlan_tagging_entity_id = int(self._mac_bridge_port_ani_entity_id + self._uni_port.entity_id
+                                     + self._tp_id)
+        extended_vlan_tagging_entity_id = self._mac_bridge_service_profile_entity_id + \
+                                          self._uni_port.mac_bridge_port_num
+        ################################################################################
+        # VLAN Tagging Filter config
+        #
+        #  EntityID will be referenced by:
+        #            - Nothing
+        #  References:
+        #            - MacBridgePortConfigurationData for the ANI/PON side
+        #
+
+        # TODO: check if its in our local mib first before blindly deleting
+        if self._tp_id != 0:
+            yield self._create_vlan_filter_entity(vlan_tagging_entity_id)
+
+        self.log.info('setting-vlan-tagging')
+        attributes = dict(
+            # Specifies the TPIDs in use and that operations in the downstream direction are
+            # inverse to the operations in the upstream direction
+            input_tpid=self._input_tpid,  # input TPID
+            output_tpid=self._output_tpid,  # output TPID
+            downstream_mode=0,  # inverse of upstream
+        )
+
+        msg = ExtendedVlanTaggingOperationConfigurationDataFrame(
+            extended_vlan_tagging_entity_id,  # Bridge Entity ID
+            attributes=attributes
+        )
+
+        frame = msg.set()
+        self.log.debug('openomci-msg', omci_msg=msg)
+        self.strobe_watchdog()
+        results = yield self._device.omci_cc.send(frame)
+        self.check_status_and_state(results, 'set-extended-vlan-tagging-operation-configuration-data')
+
+        # Onu-Transparent
+        if self._set_vlan_id == RESERVED_TRANSPARENT_VLAN:
+            # Transparently send any single tagged packet.
+            # As the onu is to be transparent, no need to create VlanTaggingFilterData ME.
+            # Any other specific rules will take priority over this, so not setting any other vlan specific rules
+            entry = VlanTaggingOperation(
+                filter_outer_priority=15,  # not an outer tag rule, ignore all other outers
+                filter_outer_vid=4096,  # ignore
+                filter_outer_tpid_de=0,  # ignore
+                filter_inner_priority=14,  # default single tagged rule
+                filter_inner_vid=4096,  # do not match on vlan value
+                filter_inner_tpid_de=0,  # do not match on tpid
+                filter_ether_type=0,  # do not filter on untagged ethertype
+                treatment_tags_to_remove=0,  # do not remove any tags
+                treatment_outer_priority=15,  # do not add outer tag
+                treatment_outer_vid=0,  # ignore
+                treatment_outer_tpid_de=0,  # ignore
+                treatment_inner_priority=15,  # do not add inner tag
+                treatment_inner_vid=0,  # ignore
+                treatment_inner_tpid_de=4  # set TPID 0x8100
+            )
+
+            attributes = dict(received_frame_vlan_tagging_operation_table=entry)
+            msg = ExtendedVlanTaggingOperationConfigurationDataFrame(
+                extended_vlan_tagging_entity_id,  # Bridge Entity ID
+                attributes=attributes
+            )
+
+            frame = msg.set()
+            self.log.debug('openomci-msg', omci_msg=msg)
+            self.strobe_watchdog()
+            results = yield self._device.omci_cc.send(frame)
+            self.check_status_and_state(results, 'set-evto-table-transparent-vlan')
+        else:
+            # Update uni side extended vlan filter
+            # filter for any set vlan - even its match tag is TRANSPARENT.
+            # For TRANSPARENT match_vlan tag case we modified vlan_pcp and treatment_tags_to_remove values during init.
+            entry = VlanTaggingOperation(
+                filter_outer_priority=15,  # This entry is not a double-tag rule
+                filter_outer_vid=4096,  # Do not filter on the outer VID value
+                filter_outer_tpid_de=0,  # Do not filter on the outer TPID field
+
+                filter_inner_priority=self._vlan_pcp,  # Filter on inner vlan
+                filter_inner_vid=self._match_vlan,  # Look for match vlan
+                filter_inner_tpid_de=0,  # Do not filter on inner TPID field
+                filter_ether_type=0,  # Do not filter on EtherType
+
+                treatment_tags_to_remove=self._treatment_tags_to_remove,
+                treatment_outer_priority=15,
+                treatment_outer_vid=0,
+                treatment_outer_tpid_de=0,
+
+                treatment_inner_priority=self._set_vlan_pcp,  # Add an inner priority
+                treatment_inner_vid=self._set_vlan_id,  # use this value as the VID in the inner VLAN tag
+                treatment_inner_tpid_de=4,  # set TPID
+            )
+
+            attributes = dict(received_frame_vlan_tagging_operation_table=entry)
+            msg = ExtendedVlanTaggingOperationConfigurationDataFrame(
+                extended_vlan_tagging_entity_id,  # Bridge Entity ID
+                attributes=attributes  # See above
+            )
+            frame = msg.set()
+            self.log.debug('openomci-msg', omci_msg=msg)
+            self.strobe_watchdog()
+            results = yield self._device.omci_cc.send(frame)
+            self.check_status_and_state(results, 'set-evto-table')
+
+    @inlineCallbacks
+    def _bulk_update_evto_and_vlan_tag_filter(self):
+        self.log.info("bulk-update-evto-and-vlan-tag-filter")
+        # First reset any existing config EVTO and vlan tag filter on the ONU
+        yield self._reset_evto_and_vlan_tag_filter()
+
+        vlan_tagging_entity_id = int(self._mac_bridge_port_ani_entity_id + self._uni_port.entity_id
+                                     + self._tp_id)
+        extended_vlan_tagging_entity_id = self._mac_bridge_service_profile_entity_id + \
+                                          self._uni_port.mac_bridge_port_num
+        attributes = dict(
+            # Specifies the TPIDs in use and that operations in the downstream direction are
+            # inverse to the operations in the upstream direction
+            input_tpid=self._input_tpid,  # input TPID
+            output_tpid=self._output_tpid,  # output TPID
+            downstream_mode=0,  # inverse of upstream
+        )
+
+        msg = ExtendedVlanTaggingOperationConfigurationDataFrame(
+            extended_vlan_tagging_entity_id,  # Bridge Entity ID
+            attributes=attributes
+        )
+
+        frame = msg.set()
+        self.log.debug('openomci-msg', omci_msg=msg)
+        self.strobe_watchdog()
+        results = yield self._device.omci_cc.send(frame)
+        self.check_status_and_state(results, 'set-extended-vlan-tagging-operation-configuration-data')
+
+        # Onu-Transparent
+        if self._set_vlan_id == RESERVED_TRANSPARENT_VLAN:
+            # Transparently send any single tagged packet.
+            # As the onu is to be transparent, no need to create VlanTaggingFilterData ME.
+            # Any other specific rules will take priority over this, so not setting any other vlan specific rules
+            attributes = dict(
+                received_frame_vlan_tagging_operation_table=
+                VlanTaggingOperation(
+                    filter_outer_priority=15,
+                    filter_outer_vid=4096,
+                    filter_outer_tpid_de=0,
+                    filter_inner_priority=14,
+                    filter_inner_vid=4096,
+                    filter_inner_tpid_de=0,
+                    filter_ether_type=0,
+                    treatment_tags_to_remove=0,
+                    treatment_outer_priority=15,
+                    treatment_outer_vid=0,
+                    treatment_outer_tpid_de=0,
+                    treatment_inner_priority=15,
+                    treatment_inner_vid=0,
+                    treatment_inner_tpid_de=4
+                )
+            )
+
+            msg = ExtendedVlanTaggingOperationConfigurationDataFrame(
+                extended_vlan_tagging_entity_id,  # Bridge Entity ID
+                attributes=attributes
+            )
+
+            frame = msg.set()
+            self.log.debug('openomci-msg', omci_msg=msg)
+            self.strobe_watchdog()
+            results = yield self._device.omci_cc.send(frame)
+            self.check_status_and_state(results, 'set-evto-table-transparent-vlan')
+
+        else:
+            # Re-Create bridge ani side vlan filter
+            forward_operation = 0x10  # VID investigation
+
+            msg = VlanTaggingFilterDataFrame(
+                vlan_tagging_entity_id,
+                vlan_tcis=[self._set_vlan_id],  # VLAN IDs
+                forward_operation=forward_operation
+            )
+            frame = msg.create()
+            self.log.debug('openomci-msg', omci_msg=msg)
+            self.strobe_watchdog()
+            results = yield self._device.omci_cc.send(frame)
+            self.check_status_and_state(results, 'flow-create-vlan-tagging-filter-data')
+            # Update uni side extended vlan filter
+            # filter for untagged
+            attributes = dict(
+                received_frame_vlan_tagging_operation_table=
+                VlanTaggingOperation(
+                    filter_outer_priority=15,
+                    filter_outer_vid=4096,
+                    filter_outer_tpid_de=0,
+                    filter_inner_priority=15,
+                    filter_inner_vid=4096,
+                    filter_inner_tpid_de=0,
+                    filter_ether_type=0,
+                    treatment_tags_to_remove=0,
+                    treatment_outer_priority=15,
+                    treatment_outer_vid=0,
+                    treatment_outer_tpid_de=0,
+                    treatment_inner_priority=0,
+                    treatment_inner_vid=self._set_vlan_id,
+                    treatment_inner_tpid_de=4
+                )
+            )
+
+            msg = ExtendedVlanTaggingOperationConfigurationDataFrame(
+                extended_vlan_tagging_entity_id,  # Bridge Entity ID
+                attributes=attributes
+            )
+
+            frame = msg.set()
+            self.log.debug('openomci-msg', omci_msg=msg)
+            self.strobe_watchdog()
+            results = yield self._device.omci_cc.send(frame)
+            self.check_status_and_state(results, 'set-evto-table-untagged')
+
+            # Update uni side extended vlan filter
+            # filter for vlan 0
+            attributes = dict(
+                received_frame_vlan_tagging_operation_table=
+                VlanTaggingOperation(
+                    filter_outer_priority=15,  # This entry is not a double-tag rule
+                    filter_outer_vid=4096,  # Do not filter on the outer VID value
+                    filter_outer_tpid_de=0,  # Do not filter on the outer TPID field
+
+                    filter_inner_priority=8,  # Filter on inner vlan
+                    filter_inner_vid=0x0,  # Look for vlan 0
+                    filter_inner_tpid_de=0,  # Do not filter on inner TPID field
+                    filter_ether_type=0,  # Do not filter on EtherType
+
+                    treatment_tags_to_remove=1,
+                    treatment_outer_priority=15,
+                    treatment_outer_vid=0,
+                    treatment_outer_tpid_de=0,
+
+                    treatment_inner_priority=8,  # Add an inner tag and insert this value as the priority
+                    treatment_inner_vid=self._set_vlan_id,  # use this value as the VID in the inner VLAN tag
+                    treatment_inner_tpid_de=4,  # set TPID
+                )
+            )
+            msg = ExtendedVlanTaggingOperationConfigurationDataFrame(
+                extended_vlan_tagging_entity_id,  # Bridge Entity ID
+                attributes=attributes  # See above
+            )
+            frame = msg.set()
+            self.log.debug('openomci-msg', omci_msg=msg)
+            self.strobe_watchdog()
+            results = yield self._device.omci_cc.send(frame)
+            self.check_status_and_state(results, 'set-evto-table-zero-tagged')