Expand field/action conversion scope of ofagent

Ofagent did not parse all fields back from protobuf to lexi,
hence ONOS was not able to confirm downloaded flows. This
made her unhappy.

Also, DHCP config info is added to ONOS netcfg.json.

Change-Id: I57ac5d3b4d14c8c52feb52e08bb420c15809238e
diff --git a/tests/utests/ofagent/test_converter.py b/tests/utests/ofagent/test_converter.py
new file mode 100644
index 0000000..e84108a
--- /dev/null
+++ b/tests/utests/ofagent/test_converter.py
@@ -0,0 +1,206 @@
+from unittest import TestCase, main
+
+from loxi import of13
+from voltha.protos import third_party
+from ofagent.converter import to_loxi
+from voltha.core.flow_decomposer import *
+
+_ = third_party
+
+
+class TestConverter(TestCase):
+
+    def gen_pb_flow_stats(self):
+
+        # device level flows
+
+        flow_stats = [
+            mk_flow_stat(
+                priority=2000,
+                match_fields=[in_port(2), vlan_vid(4096 + 4000), vlan_pcp(0)],
+                actions=[pop_vlan(), output(1)]
+            ),
+            mk_flow_stat(
+                priority=2000,
+                match_fields=[in_port(1), eth_type(0x888e)],
+                actions=[push_vlan(0x8100), set_field(vlan_vid(4096 + 4000)),
+                         output(2)]
+            ),
+            mk_flow_stat(
+                priority=1000,
+                match_fields=[in_port(1), eth_type(0x800), ip_proto(2)],
+                actions=[push_vlan(0x8100), set_field(vlan_vid(4096 + 4000)),
+                         output(2)]
+            ),
+            mk_flow_stat(
+                priority=1000,
+                match_fields=[in_port(1), eth_type(0x800), ip_proto(17),
+                              udp_src(68), udp_dst(67)],
+                actions=[push_vlan(0x8100), set_field(vlan_vid(4096 + 4000)),
+                         output(2)]
+            ),
+            mk_flow_stat(
+                priority=1000,
+                match_fields=[in_port(2), vlan_vid(4096 + 140)],
+                actions=[pop_vlan(), output(1)]
+            ),
+            mk_flow_stat(
+                priority=500,
+                match_fields=[in_port(2), vlan_vid(4096 + 1000), metadata(128)],
+                actions=[pop_vlan(), output(1)]
+            ),
+            mk_flow_stat(
+                priority=500,
+                match_fields=[in_port(1), vlan_vid(4096 + 128)],
+                actions=[
+                    push_vlan(0x8100), set_field(vlan_vid(4096 + 1000)),
+                    output(2)]
+            ),
+            mk_flow_stat(
+                priority=500,
+                match_fields=[in_port(1), vlan_vid(4096 + 129)],
+                actions=[
+                    push_vlan(0x8100), set_field(vlan_vid(4096 + 1000)),
+                    output(2)]
+            ),
+        ] + [
+            mk_flow_stat(
+                priority=500,
+                match_fields=[in_port(2), vlan_vid(4096 + 0)],
+                actions=[
+                    set_field(vlan_vid(4096 + 128)), output(1)]
+            ),
+            mk_flow_stat(
+                priority=1000,
+                match_fields=[
+                    in_port(1), eth_type(0x800), ipv4_dst(0xe4010102)],
+                actions=[output(2)]
+            ),
+            mk_flow_stat(
+                priority=1000,
+                match_fields=[
+                    in_port(1), eth_type(0x800), ipv4_dst(0xe4010104)],
+                actions=[output(2)]
+            ),
+            mk_flow_stat(
+                priority=500,
+                match_fields=[in_port(1), vlan_vid(4096 + 128)],
+                actions=[set_field(vlan_vid(4096 + 0)), output(2)]
+            ),
+            mk_flow_stat(
+                priority=500,
+                match_fields=[in_port(2), vlan_vid(0)],
+                actions=[push_vlan(0x8100), set_field(vlan_vid(4096 + 128)),
+                         output(1)]
+            )
+
+        ]
+
+        # logical device level flows
+
+        # Various controller-bound rules
+        for _in_port in (1, 2):
+            flow_stats.append(mk_flow_stat(
+                priority=2000,
+                match_fields=[in_port(_in_port), eth_type(0x888e)],
+                actions=[
+                    push_vlan(0x8100),
+                    set_field(vlan_vid(4096 + 4000)),
+                    output(ofp.OFPP_CONTROLLER)
+                ]
+            ))
+        flow_stats.append(mk_flow_stat(
+            priority=1000,
+            match_fields=[eth_type(0x800), ip_proto(2)],
+            actions=[output(ofp.OFPP_CONTROLLER)]
+        ))
+        flow_stats.append(mk_flow_stat(
+            priority=1000,
+            match_fields=[eth_type(0x800), ip_proto(17),
+                          udp_src(68), udp_dst(67)],
+            actions=[output(ofp.OFPP_CONTROLLER)]
+        ))
+
+        # Multicast channels
+        mcast_setup = (
+            (1, 0xe4010101, ()),
+            (2, 0xe4010102, (1,)),
+            (3, 0xe4010103, (2,)),
+            (4, 0xe4010104, (1, 2)),
+        )
+        for group_id, mcast_addr, ports in mcast_setup:
+            # self.lda.update_group_table(mk_multicast_group_mod(
+            #     group_id=group_id,
+            #     buckets=[
+            #         ofp.ofp_bucket(actions=[
+            #             pop_vlan(),
+            #             output(port)
+            #         ]) for port in ports
+            #     ]))
+            flow_stats.append(mk_flow_stat(
+                priority=1000,
+                match_fields=[
+                    in_port(0),
+                    eth_type(0x800),
+                    vlan_vid(4096 + 140),
+                    ipv4_dst(mcast_addr)
+                ],
+                actions=[
+                    group(group_id)
+                ]
+            ))
+
+        # Unicast channels for each subscriber
+        # Downstream flow 1 for both
+            flow_stats.append(mk_flow_stat(
+            priority=500,
+            match_fields=[
+                in_port(0),
+                vlan_vid(4096 + 1000),
+                metadata(128)
+            ],
+            actions=[pop_vlan()],
+            next_table_id=1
+        ))
+        # Downstream flow 2 and upsrteam flow 1 for each ONU
+        for port, c_vid in ((1, 101), (2, 102)):
+            flow_stats.append(mk_flow_stat(
+                priority=500,
+                match_fields=[in_port(0), vlan_vid(4096 + c_vid)],
+                actions=[set_field(vlan_vid(4096 + 0)), output(port)]
+            ))
+            # for the 0-tagged case
+            flow_stats.append(mk_flow_stat(
+                priority=500,
+                match_fields=[in_port(port), vlan_vid(4096 + 0)],
+                actions=[set_field(vlan_vid(4096 + c_vid))],
+                next_table_id=1
+            ))
+            # for the untagged case
+            flow_stats.append(mk_flow_stat(
+                priority=500,
+                match_fields=[in_port(port), vlan_vid(0)],
+                actions=[push_vlan(0x8100), set_field(vlan_vid(4096 + c_vid))],
+                next_table_id=1
+            ))
+            # Upstream flow 2 for s-tag
+            flow_stats.append(mk_flow_stat(
+                priority=500,
+                match_fields=[in_port(port), vlan_vid(4096 + c_vid)],
+                actions=[
+                    push_vlan(0x8100),
+                    set_field(vlan_vid(4096 + 1000)),
+                    output(0)
+                ]
+            ))
+
+        return flow_stats
+
+    def test_flow_spec_pb_to_loxi_conversion(self):
+        flow_stats = self.gen_pb_flow_stats()
+        for flow_stat in flow_stats:
+            loxi_flow_stats = to_loxi(flow_stat)
+
+
+if __name__ == '__main__':
+    main()
diff --git a/tests/utests/voltha/core/test_logical_device_agent.py b/tests/utests/voltha/core/test_logical_device_agent.py
index 7b2cbce..c9879ca 100644
--- a/tests/utests/voltha/core/test_logical_device_agent.py
+++ b/tests/utests/voltha/core/test_logical_device_agent.py
@@ -593,8 +593,8 @@
         ))
         self.lda._flow_table_updated(self.flows)
         self.assertEqual(len(self.device_flows['olt'].items), 2)
-        self.assertEqual(len(self.device_flows['onu1'].items), 1)
-        self.assertEqual(len(self.device_flows['onu2'].items), 1)
+        self.assertEqual(len(self.device_flows['onu1'].items), 3)
+        self.assertEqual(len(self.device_flows['onu2'].items), 3)
         self.assertEqual(len(self.device_groups['olt'].items), 0)
         self.assertEqual(len(self.device_groups['onu1'].items), 0)
         self.assertEqual(len(self.device_groups['onu2'].items), 0)
@@ -630,7 +630,8 @@
         ))
         self.lda.update_flow_table(mk_simple_flow_mod(
             priority=1000,
-            match_fields=[eth_type(0x800), ip_proto(17), udp_dst(67)],
+            match_fields=[eth_type(0x800), ip_proto(17),
+                          udp_src(68), udp_dst(67)],
             actions=[output(ofp.OFPP_CONTROLLER)]
         ))
 
@@ -669,7 +670,8 @@
             priority=500,
             match_fields=[
                 in_port(0),
-                vlan_vid(4096 + 1000)
+                vlan_vid(4096 + 1000),
+                metadata(128)
             ],
             actions=[pop_vlan()],
             next_table_id=1
@@ -741,7 +743,7 @@
         self.assertFlowsEqual(self.device_flows['olt'].items[3], mk_flow_stat(
             priority=1000,
             match_fields=[in_port(1), eth_type(0x800), ip_proto(17),
-                          udp_dst(67)],
+                          udp_src(68), udp_dst(67)],
             actions=[push_vlan(0x8100), set_field(vlan_vid(4096 + 4000)),
                      output(0)]
         ))
@@ -752,7 +754,7 @@
         ))
         self.assertFlowsEqual(self.device_flows['olt'].items[5], mk_flow_stat(
             priority=500,
-            match_fields=[in_port(0), vlan_vid(4096 + 1000)],
+            match_fields=[in_port(0), vlan_vid(4096 + 1000), metadata(128)],
             actions=[pop_vlan(), output(1)]
         ))
         self.assertFlowsEqual(self.device_flows['olt'].items[6], mk_flow_stat(