def SetupPolicyFlows(self, request, context) -> SetupFlowsResult: """ Setup flows for all subscribers, used on pipelined restarts """ self._log_grpc_payload(request) if not self._service_manager.is_app_enabled( EnforcementController.APP_NAME): context.set_code(grpc.StatusCode.UNAVAILABLE) context.set_details('Service not enabled!') return None for controller in [self._gy_app, self._enforcer_app, self._enforcement_stats]: ret = controller.check_setup_request_epoch(request.epoch) if ret is not None: return SetupFlowsResult(result=ret) fut = Future() self._loop.call_soon_threadsafe(self._setup_flows, request, fut) try: return fut.result(timeout=self._call_timeout) except concurrent.futures.TimeoutError: logging.error("SetupPolicyFlows processing timed out") return SetupFlowsResult(result=SetupFlowsResult.FAILURE)
def handle_restart( self, quota_updates: List[SubscriberQuotaUpdate], ) -> SetupFlowsResult: """ Setup the check quota flows for the controller, this is used when the controller restarts. """ # TODO Potentially we can run a diff logic but I don't think there is # benefit(we don't need stats here) self._delete_all_flows(self._datapath) self._install_default_flows(self._datapath) self.update_subscriber_quota_state(quota_updates) return SetupFlowsResult(result=SetupFlowsResult.SUCCESS)
def SetupPolicyFlows(self, request, context) -> SetupFlowsResult: """ Setup flows for all subscribers, used on pipelined restarts """ if not self._service_manager.is_app_enabled( EnforcementController.APP_NAME): context.set_code(grpc.StatusCode.UNAVAILABLE) context.set_details('Service not enabled!') return None ret = self._enforcer_app.is_ready_for_restart_recovery(request.epoch) if ret != SetupFlowsResult.SUCCESS: return SetupFlowsResult(result=ret) fut = Future() self._loop.call_soon_threadsafe(self._setup_flows, request, fut) return fut.result()
def SetupUEMacFlows(self, request, context) -> SetupFlowsResult: """ Activate a list of attached UEs """ if not self._service_manager.is_app_enabled( UEMacAddressController.APP_NAME): context.set_code(grpc.StatusCode.UNAVAILABLE) context.set_details('Service not enabled!') return None ret = self._ue_mac_app.is_ready_for_restart_recovery(request.epoch) if ret != SetupFlowsResult.SUCCESS: return SetupFlowsResult(result=ret) fut = Future() self._loop.call_soon_threadsafe(self._setup_ue_mac, request, fut) return fut.result()
def handle_restart( self, ue_requests: List[UEMacFlowRequest]) -> SetupFlowsResult: """ Setup current check quota flows. """ # TODO Potentially we can run a diff logic but I don't think there is # benefit(we don't need stats here) self.delete_all_flows(self._datapath) self._install_default_flows() for ue_req in ue_requests: self.add_ue_mac_flow(ue_req.sid.id, ue_req.mac_addr) self._loop.call_soon_threadsafe(self._setup_arp, ue_requests) self.init_finished = True return SetupFlowsResult(result=SetupFlowsResult.SUCCESS)
def SetupQuotaFlows(self, request, context) -> SetupFlowsResult: """ Activate a list of quota rules """ self._log_grpc_payload(request) if not self._service_manager.is_app_enabled( CheckQuotaController.APP_NAME): context.set_code(grpc.StatusCode.UNAVAILABLE) context.set_details('Service not enabled!') return None ret = self._check_quota_app.check_setup_request_epoch(request.epoch) if ret: return SetupFlowsResult(result=ret) fut = Future() self._loop.call_soon_threadsafe(self._setup_quota, request, fut) return fut.result()
def handle_restart( self, ue_requests: List[UEMacFlowRequest]) -> SetupFlowsResult: """ Setup current check quota flows. """ # TODO Potentially we can run a diff logic but I don't think there is # benefit(we don't need stats here) self.delete_all_flows(self._datapath) self._install_default_flows() for ue_req in ue_requests: self.add_ue_mac_flow(ue_req.sid.id, ue_req.mac_addr) if self.arp_contoller or self.arpd_controller_fut.done(): if not self.arp_contoller: self.arp_contoller = self.arpd_controller_fut.result() self.arp_contoller.handle_restart(ue_requests) return SetupFlowsResult(result=SetupFlowsResult.SUCCESS)
def SetupPolicyFlows(self, request, context) -> SetupFlowsResult: """ Setup flows for all subscribers, used on pipelined restarts """ self._log_grpc_payload(request) if not self._service_manager.is_app_enabled( EnforcementController.APP_NAME): context.set_code(grpc.StatusCode.UNAVAILABLE) context.set_details('Service not enabled!') return None for controller in [ self._gy_app, self._enforcer_app, self._enforcement_stats ]: ret = controller.check_setup_request_epoch(request.epoch) if ret: return SetupFlowsResult(result=ret) fut = Future() self._loop.call_soon_threadsafe(self._setup_flows, request, fut) return fut.result()
def setup_flows(self, request): """ Setup flows for the controller, this is used when the controller restarts. Subclasses define their own specific setup logic. """ if request.epoch != global_epoch: self.logger.warning( "Received SetupFlowsRequest has outdated epoch - %d, current " "epoch is - %d.", request.epoch, global_epoch) return SetupFlowsResult(result=SetupFlowsResult.OUTDATED_EPOCH) if self._datapath is None: self.logger.warning("Datapath not initilized, setup failed") return SetupFlowsResult(result=SetupFlowsResult.FAILURE) if self._startup_flow_controller is None: if (self._startup_flows_fut.done()): self._startup_flow_controller = self._startup_flows_fut.result( ) else: self.logger.error('Flow Startup controller is not ready') return SetupFlowsResult(result=SetupFlowsResult.FAILURE) if self.init_finished: self.logger.warning('Controller already initialized, ignoring') return SetupFlowsResult(result=SetupFlowsResult.SUCCESS) if self._clean_restart: self.delete_all_flows(self._datapath) self.logger.error('Controller is in clean restart mode, remaining ' 'flows were removed, continuing with setup.') try: startup_flows = \ self._startup_flow_controller.get_flows(self.tbl_num) except ControllerNotReadyException as err: self.logger.error('Setup failed: %s', err) return SetupFlowsResult(result=SetupFlowsResult.FAILURE) return SetupFlowsResult(result=self.setup( request.requests, request.quota_updates.updates, startup_flows))
def handle_restart(self, requests) -> SetupFlowsResult: """ Sets up the controller after the restart - Add default/missing flows if needed - Remove stale flows (not default and not in passed requsts) requests argument is controller specific """ if not self._datapath: self.logger.error('Controller restart not ready, datapath is None') return SetupFlowsResult(result=SetupFlowsResult.FAILURE) dp = self._datapath if requests is None: requests = [] if self._clean_restart: self.delete_all_flows(dp) self.cleanup_state() self.logger.info('Controller is in clean restart mode, remaining ' 'flows were removed, continuing with setup.') if self._startup_flow_controller is None: if (self._startup_flows_fut.done()): self._startup_flow_controller = self._startup_flows_fut.result( ) else: self.logger.error('Flow Startup controller is not ready') return SetupFlowsResult(result=SetupFlowsResult.FAILURE) # Workaround for controllers with multiple tables if not hasattr(self, '_tbls'): self._tbls = [self.tbl_num] try: startup_flows_map = \ {i: self._startup_flow_controller.get_flows(i) for i in self._tbls} except ControllerNotReadyException as err: self.logger.error('Setup failed: %s', err) return SetupFlowsResult(result=SetupFlowsResult.FAILURE) for tbl in startup_flows_map: self.logger.debug('Startup flows before filtering-> %s', [flow.match for flow in startup_flows_map[tbl]]) self.logger.debug('Setting up %s default rules', self.APP_NAME) default_msgs = self._get_default_flow_msgs(dp) for table, msgs_to_install in default_msgs.items(): msgs, remaining_flows = self._msg_hub \ .filter_msgs_if_not_in_flow_list(dp, msgs_to_install, startup_flows_map[table]) if msgs: chan = self._msg_hub.send(msgs, dp) self._wait_for_responses(chan, len(msgs)) startup_flows_map[table] = remaining_flows ue_msgs = self._get_ue_specific_flow_msgs(requests) for table, msgs_to_install in ue_msgs.items(): msgs, remaining_flows = self._msg_hub \ .filter_msgs_if_not_in_flow_list(dp, msgs_to_install, startup_flows_map[table]) if msgs: chan = self._msg_hub.send(msgs, dp) self._wait_for_responses(chan, len(msgs)) startup_flows_map[table] = remaining_flows for tbl in startup_flows_map: self.logger.debug('Startup extra flows that will be deleted -> %s', [flow.match for flow in startup_flows_map[tbl]]) self._remove_extra_flows(startup_flows_map) self.finish_init(requests) self.init_finished = True return SetupFlowsResult(result=SetupFlowsResult.SUCCESS)
def handle_restart( self, requests: List[ActivateFlowsRequest]) -> SetupFlowsResult: """ Sets up the controller after the restart - Add default/missing flows if needed - Remove stale flows (not default and not in passed requsts) """ if not self._datapath: self.logger.error('Controller restart not ready, datapath is None') return SetupFlowsResult.FAILURE if requests is None: requests = [] if self._clean_restart: self.delete_all_flows(self._datapath) self.cleanup_state() self.logger.info('Controller is in clean restart mode, remaining ' 'flows were removed, continuing with setup.') if self._startup_flow_controller is None: if (self._startup_flows_fut.done()): self._startup_flow_controller = self._startup_flows_fut.result( ) else: self.logger.error('Flow Startup controller is not ready') return SetupFlowsResult.FAILURE if not hasattr(self, '_tbls'): self._tbls = [self.tbl_num] try: startup_flows = \ {i: self._startup_flow_controller.get_flows(i) for i in self._tbls} except ControllerNotReadyException as err: self.logger.error('Setup failed: %s', err) return SetupFlowsResult(result=SetupFlowsResult.FAILURE) self.logger.debug('Setting up %s default rules', self.APP_NAME) remaining_flows = self._install_default_flows_if_not_installed( self._datapath, startup_flows) for tbl in startup_flows: self.logger.debug('Startup flows before filtering -> %s', [flow.match for flow in startup_flows[tbl]]) extra_flows = self._add_missing_flows(requests, remaining_flows) for tbl in startup_flows: self.logger.debug('Startup extra flows that will be deleted -> %s', [flow.match for flow in startup_flows[tbl]]) self._remove_extra_flows(extra_flows) # For now just reinsert redirection rules, this is a bit of a hack but # redirection relies on async dns request to be setup and we can't # currently do this from out synchronous setup request. So just reinsert self._process_redirection_rules(requests) # TODO I don't think this is relevant here, move to specific controller if self.proxy_controller_fut and self.proxy_controller_fut.done(): if not self.proxy_controller: self.proxy_controller = self.proxy_controller_fut.result() self.logger.info("Initialized proxy_controller %s", self.proxy_controller) self.init_finished = True return SetupFlowsResult(result=SetupFlowsResult.SUCCESS)