Ejemplo n.º 1
0
    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)
Ejemplo n.º 2
0
    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)
Ejemplo n.º 3
0
    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()
Ejemplo n.º 4
0
    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()
Ejemplo n.º 5
0
    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)
Ejemplo n.º 6
0
    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()
Ejemplo n.º 7
0
    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)
Ejemplo n.º 8
0
    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()
Ejemplo n.º 9
0
    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))
Ejemplo n.º 10
0
    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)
Ejemplo n.º 11
0
    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)