VOL-1111 - Add support for installing downstream DHCP trap flow

This is required in deployments where the DHCP server is
connected upstream to the OLT (as opposed to DHCP server
being up in the control plane) and ONOS has to relay/trap
packets to/from the upstream DHCP server.

Change-Id: Id475d0f0a0d3290b9d3507709d85f7222b7200f3
diff --git a/voltha/adapters/openolt/openolt_flow_mgr.py b/voltha/adapters/openolt/openolt_flow_mgr.py
index b1a56cf..d6cc7b6 100644
--- a/voltha/adapters/openolt/openolt_flow_mgr.py
+++ b/voltha/adapters/openolt/openolt_flow_mgr.py
@@ -22,6 +22,7 @@
 
 HSIA_FLOW_INDEX = 0  # FIXME
 DHCP_FLOW_INDEX = 1  # FIXME
+DHCP_DOWNLINK_FLOW_INDEX = 6  # FIXME
 EAPOL_FLOW_INDEX = 2  # FIXME
 EAPOL_DOWNLINK_FLOW_INDEX = 3  # FIXME
 EAPOL_DOWNLINK_SECONDARY_FLOW_INDEX = 4  # FIXME
@@ -173,7 +174,8 @@
                            classifier=classifier,
                            action=action)
 
-    def add_data_flow(self, intf_id, onu_id, priority, uplink_classifier, uplink_action):
+    def add_data_flow(self, intf_id, onu_id, priority, uplink_classifier,
+                      uplink_action):
 
         downlink_classifier = dict(uplink_classifier)
         downlink_action = dict(uplink_action)
@@ -189,8 +191,8 @@
         # To-Do right now only one GEM port is supported, so below method
         # will take care of handling all the p bits.
         # We need to revisit when mulitple gem port per p bits is needed.
-        self.add_hsia_flow(intf_id, onu_id, priority, uplink_classifier, uplink_action,
-                           downlink_classifier, downlink_action,
+        self.add_hsia_flow(intf_id, onu_id, priority, uplink_classifier,
+                           uplink_action, downlink_classifier, downlink_action,
                            HSIA_FLOW_INDEX)
 
         # Secondary EAP on the subscriber vlan
@@ -201,8 +203,9 @@
                 downlink_eapol_id=EAPOL_DOWNLINK_SECONDARY_FLOW_INDEX,
                 vlan_id=uplink_classifier['vlan_vid'])
 
-    def add_hsia_flow(self, intf_id, onu_id, priority, uplink_classifier, uplink_action,
-                      downlink_classifier, downlink_action, hsia_id):
+    def add_hsia_flow(self, intf_id, onu_id, priority, uplink_classifier,
+                      uplink_action, downlink_classifier, downlink_action,
+                      hsia_id):
 
         gemport_id = platform.mk_gemport_id(onu_id)
         flow_id = platform.mk_flow_id(intf_id, onu_id, hsia_id)
@@ -234,7 +237,8 @@
 
     def add_dhcp_trap(self, intf_id, onu_id, priority, classifier, action):
 
-        self.log.debug('add dhcp trap', classifier=classifier, action=action)
+        self.log.debug('add dhcp upstream trap', classifier=classifier,
+                       action=action)
 
         action.clear()
         action['trap_to_host'] = True
@@ -246,12 +250,35 @@
 
         upstream_flow = openolt_pb2.Flow(
             onu_id=onu_id, flow_id=flow_id, flow_type="upstream",
-            access_intf_id=intf_id, gemport_id=gemport_id, priority=priority,
-            classifier=self.mk_classifier(classifier),
+            access_intf_id=intf_id, network_intf_id=0, gemport_id=gemport_id,
+            priority=priority, classifier=self.mk_classifier(classifier),
             action=self.mk_action(action))
 
         self.stub.FlowAdd(upstream_flow)
 
+        # FIXME - Fix OpenOLT handling of downstream flows instead
+        #         of duplicating the downstream flow from the upstream
+        #         flow.
+        # FIXME - ONOS should send explicit upstream and downstream
+        #         exact dhcp trap flow.
+        classifier['udp_src'] = 67
+        classifier['udp_dst'] = 68
+        classifier['pkt_tag_type'] = 'double_tag'
+        action.pop('push_vlan', None)
+
+        flow_id = platform.mk_flow_id(intf_id, onu_id,
+                                      DHCP_DOWNLINK_FLOW_INDEX)
+
+        downstream_flow = openolt_pb2.Flow(
+            onu_id=onu_id, flow_id=flow_id, flow_type="downstream",
+            access_intf_id=intf_id, network_intf_id=0, gemport_id=gemport_id,
+            priority=priority, classifier=self.mk_classifier(classifier),
+            action=self.mk_action(action))
+
+        self.log.debug('add dhcp downstream trap', access_intf_id=intf_id,
+                       onu_id=onu_id, flow_id=flow_id)
+        self.stub.FlowAdd(downstream_flow)
+
     def add_eapol_flow(self, intf_id, onu_id, priority,
                        uplink_eapol_id=EAPOL_FLOW_INDEX,
                        downlink_eapol_id=EAPOL_DOWNLINK_FLOW_INDEX,
@@ -280,7 +307,6 @@
 
         gemport_id = platform.mk_gemport_id(onu_id)
 
-
         # Add Upstream EAPOL Flow.
 
         uplink_flow_id = platform.mk_flow_id(intf_id, onu_id, uplink_eapol_id)
@@ -370,7 +396,8 @@
                     if field.eth_type == EAP_ETH_TYPE:
                         eap_flow = True
                 if field.type == fd.IN_PORT:
-                    eap_intf_id = platform.intf_id_from_uni_port_num(field.port)
+                    eap_intf_id = platform.intf_id_from_uni_port_num(
+                        field.port)
                     eap_onu_id = platform.onu_id_from_port_num(field.port)
 
             if eap_flow:
@@ -380,4 +407,4 @@
             if eap_flow and intf_id == eap_intf_id and onu_id == eap_onu_id:
                 return (True, flow.priority)
 
-        return (False, 0)
\ No newline at end of file
+        return (False, 0)