def _delete_all_flows(self): """ Delete all flows on the device """ try: self.flows_proxy.update('/', Flows(items=[])) self.groups_proxy.update('/', FlowGroups(items=[])) except Exception, e: self.exception('flow-delete-exception', e=e)
def group_delete(self, group_mod): assert isinstance(group_mod, ofp.ofp_group_mod) groups = OrderedDict((g.desc.group_id, g) for g in self.groups_proxy.get('/').items) groups_changed = False flows_changed = False group_id = group_mod.group_id if group_id == ofp.OFPG_ALL: # TODO we must delete all flows that point to this group and # signal controller as requested by flow's flag groups = OrderedDict() groups_changed = True self.log.debug('all-groups-deleted') else: if group_id not in groups: # per openflow spec, this is not an error pass else: flows = list(self.flows_proxy.get('/').items) flows_changed, flows = self.flows_delete_by_group_id( flows, group_id) del groups[group_id] groups_changed = True self.log.debug('group-deleted', group_id=group_id) if groups_changed: self.groups_proxy.update('/', FlowGroups(items=groups.values())) if flows_changed: self.flows_proxy.update('/', Flows(items=flows))
def update_children_flows(self, device_rules_map): for device_id, (flows, groups) in device_rules_map.iteritems(): if device_id != self.device_id: self.root_proxy.update('/devices/{}/flows'.format(device_id), Flows(items=flows.values())) self.root_proxy.update('/devices/{}/flow_groups'.format( device_id), FlowGroups(items=groups.values()))
def ListDeviceFlowGroups(self, request, context): log.info('grpc-request', request=request) if '/' in request.id: context.set_details('Malformed device id \'{}\''.format( request.id)) context.set_code(StatusCode.INVALID_ARGUMENT) return FlowGroups() try: groups = self.root.get('/devices/{}/flow_groups'.format( request.id)) return groups except KeyError: context.set_details('Device \'{}\' not found'.format(request.id)) context.set_code(StatusCode.NOT_FOUND) return FlowGroups()
def _flow_table_updated(self, flows): self.log.debug('flow-table-updated', logical_device_id=self.logical_device_id, flows=flows) if self._no_flow_changes_required: # Stats changes, no need to process further self.log.debug('flow-stats-update') else: groups = self.groups_proxy.get('/').items device_rules_map = self.decompose_rules(flows.items, groups) # TODO we have to evolve this into a policy-based, event based pattern # This is a raw implementation of the specific use-case with certain # built-in assumptions, and not yet device vendor specific. The policy- # based refinement will be introduced that later. # Temporary bypass for openolt if self.accepts_direct_logical_flows: #give the logical flows directly to the adapter self.log.debug('it is an direct logical flow bypass') if self.device_adapter_agent is None: self.log.error('No device adapter agent', device_id=self.device_id, logical_device_id=self.logical_device_id) return flows_to_add = [] for f in flows.items: if f.id in self._flows_ids_to_add: flows_to_add.append(f) self.log.debug('flows to remove', flows_to_remove=self._flows_to_remove, flows_ids=self._flows_ids_to_remove) try: self.device_adapter_agent.update_logical_flows( self.device_id, flows_to_add, self._flows_to_remove, groups, device_rules_map) except Exception as e: self.log.error('logical flows bypass error', error=e, flows=flows) else: for device_id, (flows, groups) in device_rules_map.iteritems(): self.root_proxy.update( '/devices/{}/flows'.format(device_id), Flows(items=flows.values())) self.root_proxy.update( '/devices/{}/flow_groups'.format(device_id), FlowGroups(items=groups.values()))
def test_add_group(self): group_mod = mk_multicast_group_mod( group_id=2, buckets=[ ofp.ofp_bucket(actions=[pop_vlan(), output(1)]), ofp.ofp_bucket(actions=[pop_vlan(), output(2)]), ]) self.lda.update_group_table(group_mod) expected_groups = FlowGroups( items=[group_entry_from_group_mod(group_mod)]) self.assertEqual(self.groups, expected_groups)
def _group_table_updated(self, flow_groups): self.log.debug('group-table-updated', logical_device_id=self.logical_device_id, flow_groups=flow_groups) flows = self.flows_proxy.get('/').items device_flows_map = self.decompose_rules(flows, flow_groups.items) for device_id, (flows, groups) in device_flows_map.iteritems(): self.root_proxy.update('/devices/{}/flows'.format(device_id), Flows(items=flows.values())) self.root_proxy.update('/devices/{}/flow_groups'.format(device_id), FlowGroups(items=groups.values()))
def _flow_table_updated(self, flows): self.log.debug('flow-table-updated', logical_device_id=self.logical_device_id, flows=flows) # TODO we have to evolve this into a policy-based, event based pattern # This is a raw implementation of the specific use-case with certain # built-in assumptions, and not yet device vendor specific. The policy- # based refinement will be introduced that later. groups = self.groups_proxy.get('/').items device_rules_map = self.decompose_rules(flows.items, groups) for device_id, (flows, groups) in device_rules_map.iteritems(): self.root_proxy.update('/devices/{}/flows'.format(device_id), Flows(items=flows.values())) self.root_proxy.update('/devices/{}/flow_groups'.format(device_id), FlowGroups(items=groups.values()))
def group_add(self, group_mod): assert isinstance(group_mod, ofp.ofp_group_mod) groups = OrderedDict((g.desc.group_id, g) for g in self.groups_proxy.get('/').items) changed = False if group_mod.group_id in groups: self.signal_group_mod_error(ofp.OFPGMFC_GROUP_EXISTS, group_mod) else: group_entry = group_entry_from_group_mod(group_mod) groups[group_mod.group_id] = group_entry changed = True if changed: self.groups_proxy.update('/', FlowGroups(items=groups.values()))
def group_modify(self, group_mod): assert isinstance(group_mod, ofp.ofp_group_mod) groups = OrderedDict( (g.desc.group_id, g) for g in self.groups_proxy.get('/').items) changed = False if group_mod.group_id not in groups: self.signal_group_mod_error(ofp.OFPGMFC_INVALID_GROUP, group_mod) else: # replace existing group entry with new group definition group_entry = group_entry_from_group_mod(group_mod) groups[group_mod.group_id] = group_entry changed = True if changed: self.groups_proxy.update('/', FlowGroups(items=groups.values()))
def setUp(self): self.setup_mock_registry() self.flows = Flows(items=[]) self.groups = FlowGroups(items=[]) self.ld_ports = [ LogicalPort(id='0', device_id='olt', device_port_no=0, root_port=True, ofp_port=ofp.ofp_port(port_no=0)), LogicalPort(id='1', device_id='onu1', device_port_no=0, ofp_port=ofp.ofp_port(port_no=1)), LogicalPort(id='2', device_id='onu2', device_port_no=0, ofp_port=ofp.ofp_port(port_no=2)) ] self.devices = { 'olt': Device(id='olt', root=True, parent_id='id'), 'onu1': Device(id='onu1', parent_id='olt', parent_port_no=1, vlan=101), 'onu2': Device(id='onu2', parent_id='olt', parent_port_no=1, vlan=102), } self.ports = { 'olt': [ Port(port_no=0, type=Port.ETHERNET_NNI, device_id='olt'), Port(port_no=1, type=Port.PON_OLT, device_id='olt', peers=[ Port.PeerPort(device_id='onu1', port_no=1), Port.PeerPort(device_id='onu2', port_no=1) ]) ], 'onu1': [ Port(port_no=0, type=Port.ETHERNET_UNI, device_id='onu1'), Port(port_no=1, type=Port.PON_ONU, device_id='onu1', peers=[ Port.PeerPort(device_id='olt', port_no=1), ]) ], 'onu2': [ Port(port_no=0, type=Port.ETHERNET_UNI, device_id='onu2'), Port(port_no=1, type=Port.PON_ONU, device_id='onu2', peers=[ Port.PeerPort(device_id='olt', port_no=1), ]) ], } self.device_flows = {'olt': Flows(), 'onu1': Flows(), 'onu2': Flows()} self.device_groups = { 'olt': FlowGroups(), 'onu1': FlowGroups(), 'onu2': FlowGroups() } self.ld = LogicalDevice(id='id', root_device_id='olt') self.root_proxy = Mock() def get_devices(path): if path == '': return self.devices.values() if path.endswith('/ports'): return self.ports[path[:-len('/ports')]] elif path.find('/') == -1: return self.devices[path] else: raise Exception( 'Nothing to yield for path /devices/{}'.format(path)) def update_devices(path, data): if path.endswith('/flows'): self.device_flows[path[:-len('/flows')]] = data elif path.endswith('/flow_groups'): self.device_groups[path[:-len('/flow_groups')]] = data else: raise NotImplementedError( 'not handling path /devices/{}'.format(path)) self.root_proxy.get = lambda p: \ get_devices(p[len('/devices/'):]) if p.startswith('/devices') \ else None self.root_proxy.update = lambda p, d: \ update_devices(p[len('/devices/'):], d) \ if p.startswith('/devices') \ else None self.ld_proxy = Mock() self.ld_proxy.get = lambda p: \ self.ld_ports if p == '/ports' else ( self.ld if p == '/' else None ) self.flows_proxy = Mock() self.flows_proxy.get = lambda _: self.flows # always '/' path def update_flows(_, flows): # always '/' path self.flows = flows self.flows_proxy.update = update_flows self.groups_proxy = Mock() self.groups_proxy.get = lambda _: self.groups # always '/' path def update_groups(_, groups): # always '/' path self.groups = groups self.groups_proxy.update = update_groups self.core = Mock() self.core.get_proxy = lambda path: \ self.root_proxy if path == '/' else ( self.ld_proxy if path.endswith('id') else ( self.flows_proxy if path.endswith('flows') else self.groups_proxy ) ) self.lda = LogicalDeviceAgent(self.core, self.ld)