Handle flows to trap DHCP and LLDP on NNI port
Change-Id: I1801ff00023f35ad7a8710378667d8462a69af7e
diff --git a/voltha/adapters/openolt/openolt_flow_mgr.py b/voltha/adapters/openolt/openolt_flow_mgr.py
index c984fe0..4c40910 100644
--- a/voltha/adapters/openolt/openolt_flow_mgr.py
+++ b/voltha/adapters/openolt/openolt_flow_mgr.py
@@ -18,8 +18,8 @@
import grpc
from voltha.protos.openflow_13_pb2 import OFPXMC_OPENFLOW_BASIC, \
- ofp_flow_stats, ofp_match, OFPMT_OXM, Flows, FlowGroups, \
- OFPXMT_OFB_IN_PORT, OFPXMT_OFB_VLAN_VID
+ ofp_flow_stats, OFPMT_OXM, Flows, FlowGroups, OFPXMT_OFB_IN_PORT, \
+ OFPXMT_OFB_VLAN_VID
from voltha.protos.device_pb2 import Port
import voltha.core.flow_decomposer as fd
import openolt_platform as platform
@@ -33,9 +33,10 @@
EAPOL_DOWNLINK_FLOW_INDEX = 3 # FIXME
EAPOL_DOWNLINK_SECONDARY_FLOW_INDEX = 4 # FIXME
EAPOL_UPLINK_SECONDARY_FLOW_INDEX = 5 # FIXME
-
+LLDP_FLOW_INDEX = 7 # FIXME
EAP_ETH_TYPE = 0x888e
+LLDP_ETH_TYPE = 0x88cc
# FIXME - see also BRDCM_DEFAULT_VLAN in broadcom_onu.py
DEFAULT_MGMT_VLAN = 4091
@@ -53,14 +54,12 @@
self.flows_proxy = registry('core').get_proxy(
'/devices/{}/flows'.format(self.device_id))
self.root_proxy = registry('core').get_proxy('/')
- self.fd_object = fd.FlowDecomposer()
def add_flow(self, flow):
self.log.debug('add flow', flow=flow)
classifier_info = dict()
action_info = dict()
-
for field in fd.get_ofb_fields(flow):
if field.type == fd.ETH_TYPE:
classifier_info['eth_type'] = field.eth_type
@@ -117,12 +116,14 @@
self.log.debug('being taken care of by ONU', flow=flow)
return
action_info['pop_vlan'] = True
- self.log.debug('action-type-pop-vlan', in_port=classifier_info['in_port'])
+ self.log.debug('action-type-pop-vlan',
+ in_port=classifier_info['in_port'])
elif action.type == fd.PUSH_VLAN:
action_info['push_vlan'] = True
action_info['tpid'] = action.push.ethertype
self.log.debug('action-type-push-vlan',
- push_tpid=action_info['tpid'], in_port=classifier_info['in_port'])
+ push_tpid=action_info['tpid'],
+ in_port=classifier_info['in_port'])
if action.push.ethertype != 0x8100:
self.log.error('unhandled-tpid',
ethertype=action.push.ethertype)
@@ -131,8 +132,8 @@
_field = action.set_field.field.ofb_field
assert (action.set_field.field.oxm_class ==
OFPXMC_OPENFLOW_BASIC)
- self.log.debug('action-type-set-field',
- field=_field, in_port=classifier_info['in_port'])
+ self.log.debug('action-type-set-field', field=_field,
+ in_port=classifier_info['in_port'])
if _field.type == fd.VLAN_VID:
self.log.debug('set-field-type-vlan-vid',
vlan_vid=_field.vlan_vid & 0xfff)
@@ -142,7 +143,8 @@
field_type=_field.type)
else:
self.log.error('unsupported-action-type',
- action_type=action.type, in_port=classifier_info['in_port'])
+ action_type=action.type,
+ in_port=classifier_info['in_port'])
if fd.get_goto_table_id(flow) is not None and not 'pop_vlan' in \
action_info:
@@ -150,7 +152,7 @@
return
if not 'output' in action_info and 'metadata' in classifier_info:
- #find flow in the next table
+ # find flow in the next table
next_flow = self.find_next_flow(flow)
if next_flow is None:
return
@@ -159,24 +161,21 @@
if field.type == fd.VLAN_VID:
classifier_info['metadata'] = field.vlan_vid & 0xfff
-
(intf_id, onu_id) = platform.extract_access_from_flow(
classifier_info['in_port'], action_info['output'])
-
self.divide_and_add_flow(intf_id, onu_id, classifier_info,
action_info, flow)
def remove_flow(self, flow):
self.log.debug('trying to remove flows from logical flow :',
- logical_flow=flow)
+ logical_flow=flow)
device_flows_to_remove = []
device_flows = self.flows_proxy.get('/').items
for f in device_flows:
if f.cookie == flow.id:
device_flows_to_remove.append(f)
-
for f in device_flows_to_remove:
(id, direction) = self.decode_stored_id(f.id)
flow_to_remove = openolt_pb2.Flow(flow_id=id, flow_type=direction)
@@ -185,7 +184,8 @@
except grpc.RpcError as grpc_e:
if grpc_e.code() == grpc.StatusCode.NOT_FOUND:
self.log.debug('This flow does not exist on the switch, '
- 'normal after an OLT reboot', flow=flow_to_remove)
+ 'normal after an OLT reboot',
+ flow=flow_to_remove)
else:
raise grpc_e
@@ -209,7 +209,6 @@
self.log.debug('no device flow to remove for this flow (normal '
'for multi table flows)', flow=flow)
-
def divide_and_add_flow(self, intf_id, onu_id, classifier,
action, flow):
@@ -225,22 +224,27 @@
self.log.warn('igmp flow add ignored, not implemented yet')
else:
self.log.warn("Invalid-Classifier-to-handle",
- classifier=classifier,
- action=action)
+ classifier=classifier,
+ action=action)
elif 'eth_type' in classifier:
if classifier['eth_type'] == EAP_ETH_TYPE:
self.log.debug('eapol flow add')
self.add_eapol_flow(intf_id, onu_id, flow)
vlan_id = self.get_subscriber_vlan(fd.get_in_port(flow))
if vlan_id is not None:
- self.add_eapol_flow(intf_id, onu_id, flow,
+ self.add_eapol_flow(
+ intf_id, onu_id, flow,
uplink_eapol_id=EAPOL_UPLINK_SECONDARY_FLOW_INDEX,
downlink_eapol_id=EAPOL_DOWNLINK_SECONDARY_FLOW_INDEX,
vlan_id=vlan_id)
+ if classifier['eth_type'] == LLDP_ETH_TYPE:
+ self.log.debug('lldp flow add')
+ self.add_lldp_flow(intf_id, onu_id, flow, classifier,
+ action)
elif 'push_vlan' in action:
self.add_upstream_data_flow(intf_id, onu_id, classifier, action,
- flow)
+ flow)
elif 'pop_vlan' in action:
self.add_downstream_data_flow(intf_id, onu_id, classifier,
action, flow)
@@ -249,10 +253,8 @@
classifier=classifier,
action=action, flow=flow)
-
def add_upstream_data_flow(self, intf_id, onu_id, uplink_classifier,
- uplink_action, logical_flow):
-
+ uplink_action, logical_flow):
uplink_classifier['pkt_tag_type'] = 'single_tag'
@@ -263,12 +265,12 @@
# Secondary EAP on the subscriber vlan
(eap_active, eap_logical_flow) = self.is_eap_enabled(intf_id, onu_id)
if eap_active:
- self.add_eapol_flow(intf_id, onu_id, eap_logical_flow,
+ self.add_eapol_flow(
+ intf_id, onu_id, eap_logical_flow,
uplink_eapol_id=EAPOL_UPLINK_SECONDARY_FLOW_INDEX,
downlink_eapol_id=EAPOL_DOWNLINK_SECONDARY_FLOW_INDEX,
vlan_id=uplink_classifier['vlan_vid'])
-
def add_downstream_data_flow(self, intf_id, onu_id, downlink_classifier,
downlink_action, flow):
downlink_classifier['pkt_tag_type'] = 'double_tag'
@@ -321,7 +323,6 @@
self.add_flow_to_device(upstream_flow, logical_flow)
-
# FIXME - ONOS should send explicit upstream and downstream
# exact dhcp trap flow.
@@ -346,7 +347,6 @@
classifier),
action=self.mk_action(action))
-
self.add_flow_to_device(downstream_flow, downstream_logical_flow)
def add_eapol_flow(self, intf_id, onu_id, logical_flow,
@@ -393,6 +393,7 @@
downlink_classifier['vlan_vid'] = 4000 - onu_id
+
downlink_action = {}
downlink_action['push_vlan'] = True
downlink_action['vlan_vid'] = vlan_id
@@ -438,6 +439,29 @@
def reset_flows(self):
self.flows_proxy.update('/', Flows())
+ def add_lldp_flow(self, intf_id, onu_id, logical_flow, classifier, action):
+
+ self.log.debug('add lldp downstream trap', classifier=classifier,
+ action=action)
+
+ action.clear()
+ action['trap_to_host'] = True
+ classifier['pkt_tag_type'] = 'untagged'
+
+ gemport_id = platform.mk_gemport_id(onu_id)
+ flow_id = platform.mk_flow_id(intf_id, onu_id, LLDP_FLOW_INDEX)
+
+ downstream_flow = openolt_pb2.Flow(
+ onu_id=onu_id, flow_id=flow_id, flow_type="downstream",
+ access_intf_id=3, network_intf_id=0, gemport_id=gemport_id,
+ priority=logical_flow.priority,
+ classifier=self.mk_classifier(classifier),
+ action=self.mk_action(action))
+
+ self.log.debug('add lldp downstream trap', access_intf_id=intf_id,
+ onu_id=onu_id, flow_id=flow_id)
+ self.stub.FlowAdd(downstream_flow)
+
def mk_classifier(self, classifier_info):
classifier = openolt_pb2.Classifier()
@@ -523,7 +547,6 @@
if in_port == port and \
platform.intf_id_to_port_type_name(out_port) == Port.ETHERNET_NNI:
-
fields = fd.get_ofb_fields(flow)
self.log.debug('subscriber flow found', fields=fields)
for field in fields:
@@ -553,7 +576,6 @@
flows.items.extend([stored_flow])
self.flows_proxy.update('/', flows)
-
def find_next_flow(self, flow):
table_id = fd.get_goto_table_id(flow)
metadata = 0
@@ -566,20 +588,19 @@
next_flows = []
for f in flows:
if f.table_id == table_id:
- #FIXME:
+ # FIXME
if fd.get_in_port(f) == fd.get_in_port(flow) and \
fd.get_out_port(f) == metadata:
next_flows.append(f)
-
if len(next_flows) == 0:
self.log.warning('no next flow found, it may be a timing issue',
flow=flow, number_of_flows=len(flows))
reactor.callLater(5, self.add_flow, flow)
return None
- next_flows.sort(key=lambda f:f.priority, reverse=True)
+ next_flows.sort(key=lambda f: f.priority, reverse=True)
return next_flows[0]
@@ -607,4 +628,4 @@
if id >> 15 == 0x1:
return (id & 0x7fff, 'upstream')
else:
- return (id, 'downstream')
\ No newline at end of file
+ return (id, 'downstream')