Exemplo n.º 1
0
Arquivo: he.py Projeto: ViniBR01/magma
 def _install_default_flows(self, dp):
     match = MagmaMatch(in_port=self.config.he_proxy_port)
     flows.add_drop_flow(dp,
                         self.tbl_num,
                         match,
                         priority=flows.MINIMUM_PRIORITY + 1)
     match = MagmaMatch()
     flows.add_resubmit_next_service_flow(dp,
                                          self.tbl_num,
                                          match, [],
                                          priority=flows.MINIMUM_PRIORITY,
                                          resubmit_table=self.next_table)
Exemplo n.º 2
0
    def _install_default_flow_for_subscriber(self, imsi):
        """
        Add a low priority flow to drop a subscriber's traffic in the event
        that all rules have been deactivated.

        Args:
            imsi (string): subscriber id
        """
        match = MagmaMatch(imsi=encode_imsi(imsi))
        actions = []  # empty options == drop
        flows.add_drop_flow(self._datapath, self.tbl_num, match, actions,
                            priority=self.ENFORCE_DROP_PRIORITY)
Exemplo n.º 3
0
    def _install_default_flows(self, datapath: Datapath) -> None:
        """
        For each direction set the default flows to just forward to next app.

        Args:
            datapath: ryu datapath struct
        """
        parser = self._datapath.ofproto_parser
        match = MagmaMatch()
        flows.add_resubmit_next_service_flow(
            datapath,
            self.tbl_num,
            match, [],
            priority=flows.MINIMUM_PRIORITY,
            resubmit_table=self.next_main_table)

        if not self._service_manager.is_app_enabled(DPIController.APP_NAME):
            flows.add_resubmit_next_service_flow(
                self._datapath,
                self._app_set_tbl_num,
                MagmaMatch(),
                priority=flows.MINIMUM_PRIORITY,
                cookie=self.tbl_num,
                resubmit_table=self._imsi_set_tbl_num)

        flows.add_resubmit_next_service_flow(
            self._datapath,
            self._imsi_set_tbl_num,
            MagmaMatch(),
            priority=flows.MINIMUM_PRIORITY,
            cookie=self.tbl_num,
            resubmit_table=self._ipfix_sample_tbl_num)

        if self.ipfix_config.enabled and (self._dpi_enabled
                                          or self._conntrackd_enabled):
            pdp = 1
            actions = [
                parser.NXActionSample2(
                    probability=self.ipfix_config.probability,
                    collector_set_id=self.ipfix_config.collector_set_id,
                    obs_domain_id=self.ipfix_config.obs_domain_id,
                    obs_point_id=self.ipfix_config.obs_point_id,
                    apn_mac_addr=[0, 0, 0, 0, 0, 0],
                    msisdn="defau".encode('ascii'),
                    apn_name="default".encode('ascii'),
                    pdp_start_epoch=pdp.to_bytes(8, byteorder='little'),
                    sampling_port=self.ipfix_config.sampling_port)
            ]
            flows.add_drop_flow(self._datapath,
                                self._ipfix_sample_tbl_num,
                                match,
                                actions,
                                priority=flows.DEFAULT_PRIORITY)
Exemplo n.º 4
0
 def _install_ip_blocklist_flow(self, datapath):
     """
     Install flows to drop any packets with ip address blocks matching the
     blocklist.
     """
     for entry in self.config.ip_blocklist:
         ip_network = ipaddress.IPv4Network(entry['ip'])
         direction = entry.get('direction', None)
         if direction is not None and \
                 direction not in [
                     self.CONFIG_INBOUND_DIRECTION,
                     self.CONFIG_OUTBOUND_DIRECTION,
                 ]:
             self.logger.error(
                 'Invalid direction found in ip blocklist: %s',
                 direction,
             )
             continue
         # If no direction is specified, both outbound and inbound traffic
         # will be dropped.
         if direction is None or direction == self.CONFIG_INBOUND_DIRECTION:
             match = MagmaMatch(
                 direction=Direction.OUT,
                 eth_type=ether_types.ETH_TYPE_IP,
                 ipv4_dst=(
                     ip_network.network_address,
                     ip_network.netmask,
                 ),
             )
             flows.add_drop_flow(
                 datapath,
                 self.tbl_num,
                 match,
                 [],
                 priority=flows.DEFAULT_PRIORITY,
             )
         if direction is None or \
                 direction == self.CONFIG_OUTBOUND_DIRECTION:
             match = MagmaMatch(
                 direction=Direction.IN,
                 eth_type=ether_types.ETH_TYPE_IP,
                 ipv4_src=(
                     ip_network.network_address,
                     ip_network.netmask,
                 ),
             )
             flows.add_drop_flow(
                 datapath,
                 self.tbl_num,
                 match,
                 [],
                 priority=flows.DEFAULT_PRIORITY,
             )
Exemplo n.º 5
0
    def add_ue_sample_flow(self, imsi: str, msisdn: str,
                           apn_mac_addr: str, apn_name: str,
                           pdp_start_time: int) -> None:
        """
        Install a flow to sample packets for IPFIX for specific imsi

        Args:
            imsi (string): subscriber to install rule for
            msisdn (string): msisdn string
            apn_mac_addr (string): AP mac address string
            apn_name (string): AP name
        """
        if self._datapath is None:
            self.logger.error('Datapath not initialized for adding flows')
            return

        if not self.ipfix_config.enabled:
            #TODO logging higher than debug here will provide too much noise
            # possible fix is making ipfix a dynamic service enabled from orc8r
            self.logger.debug('IPFIX export dst not setup for adding flows')
            return

        parser = self._datapath.ofproto_parser
        if not apn_mac_addr or '-' not in apn_mac_addr:
            apn_mac_bytes = [0, 0, 0, 0, 0, 0]
        else:
            apn_mac_bytes = [int(a, 16) for a in apn_mac_addr.split('-')]

        if not msisdn:
            msisdn='no_msisdn'

        actions = [parser.NXActionSample2(
            probability=self.ipfix_config.probability,
            collector_set_id=self.ipfix_config.collector_set_id,
            obs_domain_id=self.ipfix_config.obs_domain_id,
            obs_point_id=self.ipfix_config.obs_point_id,
            apn_mac_addr=apn_mac_bytes,
            msisdn=msisdn.encode('ascii'),
            apn_name=apn_name.encode('ascii'),
            pdp_start_epoch=pdp_start_time.to_bytes(8, byteorder='little'),
            sampling_port=self.ipfix_config.sampling_port)]

        match = MagmaMatch(imsi=encode_imsi(imsi))
        if self._dpi_enabled or self._conntrackd_enabled:
            flows.add_drop_flow(
                self._datapath, self._ipfix_sample_tbl_num, match, actions,
                priority=flows.UE_FLOW_PRIORITY)
        else:
            flows.add_resubmit_next_service_flow(
                self._datapath, self._ipfix_sample_tbl_num, match, actions,
                priority=flows.UE_FLOW_PRIORITY,
                resubmit_table=self.next_main_table)
Exemplo n.º 6
0
 def _install_default_arp_drop_flow(self, datapath):
     """
     Install default drop flow for all unmatched arps
     """
     # Drop all other ARPs
     match = MagmaMatch(eth_type=ether_types.ETH_TYPE_ARP)
     flows.add_drop_flow(
         datapath,
         self.table_num,
         match,
         [],
         priority=flows.DEFAULT_PRIORITY,
     )
Exemplo n.º 7
0
 def _install_drop_rule_for_untagged_arps(self, datapath):
     """
     Install default drop flow for all unmatched arps
     """
     # Drop all other ARPs
     match = MagmaMatch(eth_type=ether_types.ETH_TYPE_ARP, imsi=0)
     flows.add_drop_flow(
         datapath,
         self.table_num,
         match,
         [],
         priority=flows.UE_FLOW_PRIORITY - 1,
     )
Exemplo n.º 8
0
    def _install_default_flows(self, datapath):
        parser = datapath.ofproto_parser

        match = MagmaMatch(eth_type=ether_types.ETH_TYPE_IP,
                           ct_state=(0x0, self.CT_TRK))
        actions = [
            parser.NXActionCT(flags=0x0,
                              zone_src=None,
                              zone_ofs_nbits=ofs_nbits(14, 15),
                              recirc_table=self.conntrack_scratch,
                              alg=0,
                              actions=[])
        ]
        flows.add_resubmit_next_service_flow(datapath,
                                             self.tbl_num,
                                             match,
                                             actions,
                                             priority=flows.DEFAULT_PRIORITY,
                                             resubmit_table=self.next_table)

        # Match all new connections on scratch table
        match = MagmaMatch(eth_type=ether_types.ETH_TYPE_IP,
                           ct_zone=ofs_nbits(14, 15),
                           ct_state=(self.CT_NEW | self.CT_TRK,
                                     self.CT_NEW | self.CT_TRK))
        actions = [
            parser.NXActionCT(flags=0x1,
                              zone_src=None,
                              zone_ofs_nbits=ofs_nbits(14, 15),
                              recirc_table=self.connection_event_table,
                              alg=0,
                              actions=[])
        ]
        flows.add_drop_flow(datapath,
                            self.conntrack_scratch,
                            match,
                            actions,
                            priority=flows.DEFAULT_PRIORITY)

        match = MagmaMatch(eth_type=ether_types.ETH_TYPE_IP)
        flows.add_resubmit_next_service_flow(datapath,
                                             self.tbl_num,
                                             match, [],
                                             priority=flows.MINIMUM_PRIORITY,
                                             resubmit_table=self.next_table)
Exemplo n.º 9
0
    def _packet_in_handler(self, ev):
        msg = ev.msg
        pkt = packet.Packet(msg.data)
        pkt_ipv4 = pkt.get_protocol(ipv4.ipv4)
        if pkt_ipv4 is None:
            return None

        dst = pkt_ipv4.dst
        if dst is None:
            return None
        # For sending notification to SMF using GRPC
        self._send_message_interface(dst, msg.cookie)
        # Add flow for paging with hard time.
        match = MagmaMatch(eth_type=ether_types.ETH_TYPE_IP, ipv4_dst=dst)

        flows.add_drop_flow(self._datapath, self.tbl_num, match, [],
                            priority = Utils.PAGING_RULE_DROP_PRIORITY,
                            hard_timeout= self.config.paging_timeout)
Exemplo n.º 10
0
 def _install_default_flows(self, datapath):
     """
     Adds default flows for access control.
         For normal(ip blocklist table):
             Forward uplink to next table
             Forward downlink to scratch table
         For scratch table:
             Drop all unmatched traffic
     """
     flows.add_resubmit_next_service_flow(
         datapath,
         self.tbl_num,
         MagmaMatch(direction=Direction.IN),
         [],
         priority=flows.MINIMUM_PRIORITY,
         resubmit_table=self.next_table,
     )
     flows.add_resubmit_next_service_flow(
         datapath,
         self.tbl_num,
         MagmaMatch(direction=Direction.OUT),
         [],
         priority=flows.MINIMUM_PRIORITY,
         resubmit_table=self._tunnel_acl_scratch,
     )
     if self.config.setup_type == 'CWF':
         flows.add_drop_flow(
             datapath,
             self._tunnel_acl_scratch,
             MagmaMatch(),
             [],
             priority=flows.MINIMUM_PRIORITY,
         )
     else:
         # TODO add LTE WLAN peers
         flows.add_resubmit_next_service_flow(
             datapath,
             self._tunnel_acl_scratch,
             MagmaMatch(),
             [],
             priority=flows.MINIMUM_PRIORITY,
             resubmit_table=self.next_table,
         )
Exemplo n.º 11
0
 def _install_ip_blocking_flow(self, datapath, ip_network, direction,
                               ip_version):
     """
     Install flows to drop any packets with ip address blocks matching the
     blocklist.
     """
     if direction and direction not in [
             self.CONFIG_INBOUND_DIRECTION,
             self.CONFIG_OUTBOUND_DIRECTION,
     ]:
         self.logger.error(
             'Invalid direction found in ip blocklist: %s',
             direction,
         )
         return
     # If no direction is specified, both outbound and inbound traffic
     # will be dropped.
     if direction is None or direction == self.CONFIG_INBOUND_DIRECTION:
         match = AccessControlController._create_magma_match_blocking_flow_out(
             ip_version,
             ip_network,
         )
         flows.add_drop_flow(
             datapath,
             self.tbl_num,
             match,
             [],
             priority=flows.DEFAULT_PRIORITY,
         )
     if direction is None or direction == self.CONFIG_OUTBOUND_DIRECTION:
         match = AccessControlController._create_magma_match_blocking_flow_in(
             ip_version,
             ip_network,
         )
         flows.add_drop_flow(
             datapath,
             self.tbl_num,
             match,
             [],
             priority=flows.DEFAULT_PRIORITY,
         )
Exemplo n.º 12
0
    def setup_cwf_redirect(self, datapath, loop, redirect_request):
        """
        Add flows to forward traffic to the redirection server for cwf networks

        1) Intercept tcp traffic to the web to the redirection server, which
            completes the tcp handshake. Also overwrite UE src ip to match the
            subnet of the redirection server.
            This is done by assigning an internal IP per each subscriber.
            Add an OVS flow with a learn action (flow catches inbound tcp http
            packets, while learn action creates another flow that rewrites
            packet back to send to ue)

        2) Add flows to allow UDP traffic so DNS queries can go through.
            Add flows with a higher priority that allow traffic to and
            from the address provided in redirect rule.

        TODO we might want to track stats for these rules and report to sessiond
        """
        if not self._cwf_args_set:
            raise RedirectException("Can't install cwf redirection, missing"
                                    "cwf specific args, call set_cwf_args()")
        imsi = redirect_request.imsi
        rule = redirect_request.rule
        rule_num = redirect_request.rule_num
        rule_version = redirect_request.rule_version
        priority = redirect_request.priority
        if rule.redirect.address_type == rule.redirect.URL:
            self._install_url_bypass_flows(datapath, loop, imsi, rule,
                                           rule_num, rule_version, priority)
        elif rule.redirect.address_type == rule.redirect.IPv4:
            self._install_ipv4_bypass_flows(datapath, imsi, rule, rule_num,
                                            rule_version, priority,
                                            [rule.redirect.server_address])

        parser = datapath.ofproto_parser
        # TODO use subscriber ip_addr to generate internal IP and release
        # internal IP when subscriber disconnects or redirection flow is removed
        internal_ip = self._internal_ip_allocator.next_ip()

        self._save_redirect_entry(internal_ip, rule.redirect)
        #TODO check if we actually need this, dns might already be allowed
        self._install_dns_flows(datapath, imsi, rule, rule_num, rule_version,
                                priority)

        match_tcp_80 = MagmaMatch(imsi=encode_imsi(imsi),
                                  eth_type=ether_types.ETH_TYPE_IP,
                                  ip_proto=IPPROTO_TCP,
                                  direction=Direction.OUT,
                                  tcp_dst=80)
        match_tcp_8008 = MagmaMatch(imsi=encode_imsi(imsi),
                                    eth_type=ether_types.ETH_TYPE_IP,
                                    ip_proto=IPPROTO_TCP,
                                    direction=Direction.OUT,
                                    tcp_dst=8080)
        match_tcp_8080 = MagmaMatch(imsi=encode_imsi(imsi),
                                    eth_type=ether_types.ETH_TYPE_IP,
                                    ip_proto=IPPROTO_TCP,
                                    direction=Direction.OUT,
                                    tcp_dst=8008)
        actions = [
            parser.NXActionLearn(
                table_id=self._mac_rewrite_scratch,
                priority=flows.UE_FLOW_PRIORITY,
                cookie=rule_num,
                specs=[
                    parser.NXFlowSpecMatch(src=ether_types.ETH_TYPE_IP,
                                           dst=('eth_type_nxm', 0),
                                           n_bits=16),
                    parser.NXFlowSpecMatch(src=IPPROTO_TCP,
                                           dst=('ip_proto_nxm', 0),
                                           n_bits=8),
                    parser.NXFlowSpecMatch(src=int(
                        ipaddress.IPv4Address(self._bridge_ip)),
                                           dst=('ipv4_src_nxm', 0),
                                           n_bits=32),
                    parser.NXFlowSpecMatch(src=int(internal_ip),
                                           dst=('ipv4_dst_nxm', 0),
                                           n_bits=32),
                    parser.NXFlowSpecMatch(src=('tcp_src_nxm', 0),
                                           dst=('tcp_dst_nxm', 0),
                                           n_bits=16),
                    parser.NXFlowSpecMatch(src=self._redirect_port,
                                           dst=('tcp_src_nxm', 0),
                                           n_bits=16),
                    parser.NXFlowSpecLoad(src=('eth_src_nxm', 0),
                                          dst=('eth_dst_nxm', 0),
                                          n_bits=48),
                    parser.NXFlowSpecLoad(src=encode_imsi(imsi),
                                          dst=(IMSI_REG, 0),
                                          n_bits=64),
                    parser.NXFlowSpecLoad(src=('ipv4_src_nxm', 0),
                                          dst=('ipv4_dst_nxm', 0),
                                          n_bits=32),
                    parser.NXFlowSpecLoad(src=('ipv4_dst_nxm', 0),
                                          dst=('ipv4_src_nxm', 0),
                                          n_bits=32),
                    parser.NXFlowSpecLoad(src=('tcp_dst_nxm', 0),
                                          dst=('tcp_src_nxm', 0),
                                          n_bits=16),
                ]),
            parser.OFPActionSetField(ipv4_src=str(internal_ip)),
            parser.OFPActionSetField(ipv4_dst=self._bridge_ip),
            parser.OFPActionSetField(eth_dst=self._bridge_mac),
            parser.OFPActionSetField(tcp_dst=self._redirect_port),
        ]
        flows.add_output_flow(datapath,
                              self.main_tbl_num,
                              match_tcp_80,
                              actions,
                              priority=flows.UE_FLOW_PRIORITY,
                              cookie=rule_num,
                              output_port=OFPP_LOCAL)
        flows.add_output_flow(datapath,
                              self.main_tbl_num,
                              match_tcp_8008,
                              actions,
                              priority=flows.UE_FLOW_PRIORITY,
                              cookie=rule_num,
                              output_port=OFPP_LOCAL)
        flows.add_output_flow(datapath,
                              self.main_tbl_num,
                              match_tcp_8080,
                              actions,
                              priority=flows.UE_FLOW_PRIORITY,
                              cookie=rule_num,
                              output_port=OFPP_LOCAL)

        # Add flows for vlan traffic too (we need to pop vlan for flask server)
        # In ryu vlan_vid=(0x1000, 0x1000) matches all vlans
        match_tcp_80_vlan = MagmaMatch(imsi=encode_imsi(imsi),
                                       eth_type=ether_types.ETH_TYPE_IP,
                                       ip_proto=IPPROTO_TCP,
                                       direction=Direction.OUT,
                                       tcp_dst=80,
                                       vlan_vid=(0x1000, 0x1000))
        match_tcp_8008_vlan = MagmaMatch(imsi=encode_imsi(imsi),
                                         eth_type=ether_types.ETH_TYPE_IP,
                                         ip_proto=IPPROTO_TCP,
                                         direction=Direction.OUT,
                                         tcp_dst=8080,
                                         vlan_vid=(0x1000, 0x1000))
        match_tcp_8080_vlan = MagmaMatch(imsi=encode_imsi(imsi),
                                         eth_type=ether_types.ETH_TYPE_IP,
                                         ip_proto=IPPROTO_TCP,
                                         direction=Direction.OUT,
                                         tcp_dst=8008,
                                         vlan_vid=(0x1000, 0x1000))
        actions.append(parser.OFPActionPopVlan())
        flows.add_output_flow(datapath,
                              self.main_tbl_num,
                              match_tcp_80_vlan,
                              actions,
                              priority=flows.UE_FLOW_PRIORITY + 1,
                              cookie=rule_num,
                              output_port=OFPP_LOCAL)
        flows.add_output_flow(datapath,
                              self.main_tbl_num,
                              match_tcp_8008_vlan,
                              actions,
                              priority=flows.UE_FLOW_PRIORITY + 1,
                              cookie=rule_num,
                              output_port=OFPP_LOCAL)
        flows.add_output_flow(datapath,
                              self.main_tbl_num,
                              match_tcp_8080_vlan,
                              actions,
                              priority=flows.UE_FLOW_PRIORITY + 1,
                              cookie=rule_num,
                              output_port=OFPP_LOCAL)

        # TODO cleanup, make this a default rule in the ue_mac table
        ue_tbl = 0
        ue_next_tbl = 1
        # Allows traffic back from the flask server
        match = MagmaMatch(in_port=OFPP_LOCAL)
        actions = [
            parser.NXActionResubmitTable(table_id=self._mac_rewrite_scratch)
        ]
        flows.add_resubmit_next_service_flow(datapath,
                                             ue_tbl,
                                             match,
                                             actions=actions,
                                             priority=flows.DEFAULT_PRIORITY,
                                             resubmit_table=ue_next_tbl)
        match = MagmaMatch(imsi=encode_imsi(imsi),
                           eth_type=ether_types.ETH_TYPE_IP,
                           ip_proto=IPPROTO_TCP,
                           direction=Direction.IN,
                           in_port=OFPP_LOCAL)
        flows.add_resubmit_next_service_flow(datapath,
                                             self.main_tbl_num,
                                             match, [],
                                             priority=flows.DEFAULT_PRIORITY,
                                             cookie=rule_num,
                                             resubmit_table=self._egress_table)

        # Mac doesn't matter as we rewrite it anwyays
        mac_addr = '01:02:03:04:05:06'
        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.set_incoming_arp_flows(datapath, internal_ip,
                                                       mac_addr)

        # Drop all other traffic that doesn't match
        match = MagmaMatch(imsi=encode_imsi(imsi))
        flows.add_drop_flow(datapath,
                            self.main_tbl_num,
                            match, [],
                            priority=flows.MINIMUM_PRIORITY + 1,
                            cookie=rule_num)
Exemplo n.º 13
0
    def _install_scratch_table_flows(self, datapath, imsi, rule, rule_num,
                                     rule_version, priority):
        """
        The flow action for subscribers that need to be redirected does 2 things
            * Forward requests from subscriber to the internal http server
            * Instantiate a flow that matches response packets from the server
              and sends them back to subscriber
        Match: incoming tcp traffic with port 80, direction out
        Action:
            1) Set reg2 to rule_num
            2) Set ip dst to server ip
            3) Output to table 20
            4) Apply LearnAction:
            LearnAction(adds new flow for every pkt flow that hits this rule)
                1) Match ip packets
                2) Match tcp protocol
                3) Match packets from LOCAL port
                4) Match ip src = server ip
                5) Match ip dst = current flow ip src
                6) Match tcp src = current flow tcp dst
                7) Match tcp dst = current flow tcp src
                8) Load ip src = current flow ip dst
                9) Output through gtp0
        """
        parser = datapath.ofproto_parser
        match_http = MagmaMatch(eth_type=ether_types.ETH_TYPE_IP,
                                ip_proto=IPPROTO_TCP,
                                tcp_dst=80,
                                imsi=encode_imsi(imsi),
                                direction=Direction.OUT)
        of_note = parser.NXActionNote(list(rule.id.encode()))

        actions = [
            parser.NXActionLearn(
                table_id=self.main_tbl_num,
                priority=priority,
                cookie=rule_num,
                specs=[
                    parser.NXFlowSpecMatch(src=ether_types.ETH_TYPE_IP,
                                           dst=('eth_type_nxm', 0),
                                           n_bits=16),
                    parser.NXFlowSpecMatch(src=IPPROTO_TCP,
                                           dst=('ip_proto_nxm', 0),
                                           n_bits=8),
                    parser.NXFlowSpecMatch(src=Direction.IN,
                                           dst=(DIRECTION_REG, 0),
                                           n_bits=32),
                    parser.NXFlowSpecMatch(src=int(
                        ipaddress.IPv4Address(self._bridge_ip)),
                                           dst=('ipv4_src_nxm', 0),
                                           n_bits=32),
                    parser.NXFlowSpecMatch(src=('ipv4_src_nxm', 0),
                                           dst=('ipv4_dst_nxm', 0),
                                           n_bits=32),
                    parser.NXFlowSpecMatch(src=('tcp_src_nxm', 0),
                                           dst=('tcp_dst_nxm', 0),
                                           n_bits=16),
                    parser.NXFlowSpecMatch(src=self._redirect_port,
                                           dst=('tcp_src_nxm', 0),
                                           n_bits=16),
                    parser.NXFlowSpecMatch(src=encode_imsi(imsi),
                                           dst=(IMSI_REG, 0),
                                           n_bits=64),
                    parser.NXFlowSpecLoad(src=('ipv4_dst_nxm', 0),
                                          dst=('ipv4_src_nxm', 0),
                                          n_bits=32),
                    parser.NXFlowSpecLoad(src=80,
                                          dst=('tcp_src_nxm', 0),
                                          n_bits=16),
                    # Learn doesn't support resubmit to table, so send directly
                    parser.NXFlowSpecOutput(src=('in_port', 0),
                                            dst="",
                                            n_bits=16),
                ]),
            parser.NXActionRegLoad2(dst=SCRATCH_REGS[0],
                                    value=self.REDIRECT_PROCESSED),
            parser.OFPActionSetField(ipv4_dst=self._bridge_ip),
            parser.OFPActionSetField(tcp_dst=self._redirect_port),
            of_note,
        ]
        actions += self._load_rule_actions(parser, rule_num, rule_version)

        flows.add_resubmit_current_service_flow(
            datapath,
            self._scratch_tbl_num,
            match_http,
            actions,
            priority=priority,
            cookie=rule_num,
            hard_timeout=rule.hard_timeout,
            resubmit_table=self.main_tbl_num)

        match = MagmaMatch(imsi=encode_imsi(imsi))
        action = []
        flows.add_drop_flow(datapath,
                            self._scratch_tbl_num,
                            match,
                            action,
                            priority=flows.MINIMUM_PRIORITY + 1,
                            cookie=rule_num)