PONSIM: PON simulator with real dataplane handling
This was needed because neither CPQD nor OVS can handle
both zero-tagged packets and 802.1ad (QinQ).
- extensive unittest proves ponsim functional correctness
(for the common use-cases needed in the PON scenario)
- integrated with frameio and coupled with a rather
simple gRPC NBI, ponsim can be operated from Voltha
just like a real PON system
- posim_olt/_onu adapters added to Voltha to work on
ponsim
- CLI can be used to preprovision and activate a PONSIM
instance (e.g., preprovision_olt -t ponsim_olt -H localhost:50060)
- Some of olt-oftest:olt-complex testcases can be run on
the ponsim device (in vagrant/Ubuntu environment),
but there are some remaining issues to work out:
- barrier calls in OF do not guaranty that the flow
is already installed on the device. This is a generic
issue, not just for ponsim.
- the whole test framework is inconsistent about zero-
tagged vs. untagged frames at the ONUs, while ponsim
is rather pedantica and does exactly what was defined
in the flows.
Change-Id: I0dd564c932416ae1566935492134cb5b08113bdc
diff --git a/voltha/core/adapter_agent.py b/voltha/core/adapter_agent.py
index 0c5448f..3bf8857 100644
--- a/voltha/core/adapter_agent.py
+++ b/voltha/core/adapter_agent.py
@@ -31,6 +31,7 @@
from voltha.protos.voltha_pb2 import DeviceGroup, LogicalDevice, \
LogicalPort, AdminState
from voltha.registry import registry
+from voltha.core.flow_decomposer import OUTPUT
@implementer(IAdapterAgent)
@@ -64,11 +65,11 @@
try:
adapter = self.adapter_cls(self, config)
yield adapter.start()
+ self.adapter = adapter
+ self.adapter_node_proxy = self._update_adapter_node()
+ self._update_device_types()
except Exception, e:
self.log.exception(e)
- self.adapter = adapter
- self.adapter_node_proxy = self._update_adapter_node()
- self._update_device_types()
self.log.info('started')
returnValue(self)
@@ -199,6 +200,10 @@
return i
i += 1
+ def get_logical_device(self, logical_device_id):
+ return self.root_proxy.get('/logical_devices/{}'.format(
+ logical_device_id))
+
def create_logical_device(self, logical_device):
assert isinstance(logical_device, LogicalDevice)
@@ -210,8 +215,24 @@
self._make_up_to_date('/logical_devices',
logical_device.id, logical_device)
+ self.event_bus.subscribe(
+ topic='packet-out:{}'.format(logical_device.id),
+ callback=lambda _, p: self.receive_packet_out(logical_device.id, p)
+ )
+
return logical_device
+ def receive_packet_out(self, logical_device_id, ofp_packet_out):
+
+ def get_port_out(opo):
+ for action in opo.actions:
+ if action.type == OUTPUT:
+ return action.output.port
+
+ out_port = get_port_out(ofp_packet_out)
+ frame = ofp_packet_out.data
+ self.adapter.receive_packet_out(logical_device_id, out_port, frame)
+
def add_logical_port(self, logical_device_id, port):
assert isinstance(port, LogicalPort)
self._make_up_to_date(
diff --git a/voltha/core/logical_device_agent.py b/voltha/core/logical_device_agent.py
index f11247e..7dbf0b5 100644
--- a/voltha/core/logical_device_agent.py
+++ b/voltha/core/logical_device_agent.py
@@ -17,23 +17,23 @@
"""
Model that captures the current state of a logical device
"""
-import threading
from collections import OrderedDict
import structlog
from common.event_bus import EventBusClient
+from common.frameio.frameio import hexify
from voltha.core.config.config_proxy import CallbackType
from voltha.core.device_graph import DeviceGraph
from voltha.core.flow_decomposer import FlowDecomposer, \
flow_stats_entry_from_flow_mod_message, group_entry_from_group_mod, \
- mk_flow_stat, in_port, vlan_vid, vlan_pcp, pop_vlan, output, set_field
+ mk_flow_stat, in_port, vlan_vid, vlan_pcp, pop_vlan, output, set_field, \
+ push_vlan
from voltha.protos import third_party
from voltha.protos import openflow_13_pb2 as ofp
from voltha.protos.device_pb2 import Port
from voltha.protos.logical_device_pb2 import LogicalPort
from voltha.protos.openflow_13_pb2 import Flows, FlowGroups
-from voltha.registry import registry
_ = third_party
@@ -450,16 +450,9 @@
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ PACKET_OUT ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def packet_out(self, ofp_packet_out):
- self.log.debug('packet-out', packet=ofp_packet_out)
- print threading.current_thread().name
- print 'PACKET_OUT:', ofp_packet_out
- # TODO for debug purposes, lets turn this around and send it back
- if 0:
- self.packet_in(ofp.ofp_packet_in(
- buffer_id=ofp_packet_out.buffer_id,
- reason=ofp.OFPR_NO_MATCH,
- data=ofp_packet_out.data
- ))
+ self.log.info('packet-out', packet=ofp_packet_out)
+ topic = 'packet-out:{}'.format(self.logical_device_id)
+ self.event_bus.publish(topic, ofp_packet_out)
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ PACKET_IN ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -485,8 +478,8 @@
self.packet_in(packet_in)
def packet_in(self, ofp_packet_in):
- # TODO
- print 'PACKET_IN:', ofp_packet_in
+ self.log.info('packet-in', logical_device_id=self.logical_device_id,
+ pkt=ofp_packet_in, data=hexify(ofp_packet_in.data))
self.local_handler.send_packet_in(
self.logical_device_id, ofp_packet_in)
@@ -630,7 +623,30 @@
set_field(vlan_vid(ofp.OFPVID_PRESENT | device.vlan)),
output(upstream_ports[0].port_no)
]
- )
+ ),
+ mk_flow_stat(
+ priority=500,
+ match_fields=[
+ in_port(downstream_ports[0].port_no),
+ vlan_vid(0)
+ ],
+ actions=[
+ push_vlan(0x8100),
+ set_field(vlan_vid(ofp.OFPVID_PRESENT | device.vlan)),
+ output(upstream_ports[0].port_no)
+ ]
+ ),
+ mk_flow_stat(
+ priority=500,
+ match_fields=[
+ in_port(upstream_ports[0].port_no),
+ vlan_vid(ofp.OFPVID_PRESENT | device.vlan)
+ ],
+ actions=[
+ set_field(vlan_vid(ofp.OFPVID_PRESENT | 0)),
+ output(downstream_ports[0].port_no)
+ ]
+ ),
])
groups = OrderedDict()
return flows, groups