Esempio n. 1
0
    def _install_uplink_tunnel_flows(
        self, priority: int, i_teid: int,
        gtp_portno: int, sid: int,
    ):

        parser = self._datapath.ofproto_parser
        match = MagmaMatch(tunnel_id=i_teid, in_port=gtp_portno)
        actions = [
            parser.OFPActionSetField(eth_src=GTP_PORT_MAC),
            parser.OFPActionSetField(eth_dst="ff:ff:ff:ff:ff:ff"),
            parser.NXActionRegLoad2(dst=INGRESS_TUN_ID_REG, value=i_teid),
        ]
        if sid:
            actions.append(parser.OFPActionSetField(metadata=sid))
        flows.add_resubmit_next_service_flow(
            self._datapath, self.tbl_num, match,
            actions=actions, priority=priority,
            reset_default_register=False,
            resubmit_table=self.next_table,
        )
Esempio n. 2
0
 def _install_default_eth_dst_flow(self, datapath):
     """
     Add lower-pri flow rule to set `eth_dst` on outgoing packets to the
     specified MAC address.
     """
     self.logger.info('Setting default eth_dst to %s',
                      self.config.virtual_iface)
     parser = datapath.ofproto_parser
     match = MagmaMatch(eth_type=ether_types.ETH_TYPE_IP,
                        direction=Direction.OUT)
     actions = [
         parser.NXActionRegLoad2(dst='eth_dst',
                                 value=self.config.virtual_mac),
     ]
     flows.add_resubmit_next_service_flow(datapath,
                                          self.table_num,
                                          match,
                                          actions,
                                          priority=flows.DEFAULT_PRIORITY,
                                          resubmit_table=self.next_table)
Esempio n. 3
0
    def _get_default_flow_msgs(self, datapath) -> DefaultMsgsMap:
        """
        Gets the default flow msg that forwards to next service

        Args:
            datapath: ryu datapath struct
        Returns:
            The list of default msgs to add
        """
        match = MagmaMatch()
        msg = flows.get_add_resubmit_next_service_flow_msg(
            datapath,
            self.tbl_num,
            match,
            [],
            priority=flows.MINIMUM_PRIORITY,
            resubmit_table=self.next_main_table,
        )

        return {self.tbl_num: [msg]}
Esempio n. 4
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)
Esempio n. 5
0
    def _get_default_flow_msgs(self, datapath) -> DefaultMsgsMap:
        """
        Gets the default flow msg that forward to stats table(traffic will be
        dropped because stats table doesn't forward anything)

        Args:
            datapath: ryu datapath struct
        Returns:
            The list of default msgs to add
        """
        match = MagmaMatch()
        msg = flows.get_add_resubmit_next_service_flow_msg(
            datapath,
            self.tbl_num,
            match, [],
            priority=flows.MINIMUM_PRIORITY,
            resubmit_table=self._enforcement_stats_tbl,
            cookie=self.DEFAULT_FLOW_COOKIE)

        return {self.tbl_num: [msg]}
Esempio n. 6
0
def delete_all_flows_from_table(datapath, table, retries=3, cookie=None):
    """
    Delete all flows from a table.

    Args:
        datapath (ryu.controller.controller.Datapath): Datapath to configure
        table (int): Table to clear
        retries (int): retry attempts on failure

    Raises:
        MagmaOFError: if the flows can't be deleted
    """
    empty_match = MagmaMatch()
    cookie_match = {}
    if cookie is not None:
        cookie_match = {
            'cookie': cookie,
            'cookie_mask': OVS_COOKIE_MATCH_ALL,
        }
    delete_flow(datapath, table, empty_match, retries=retries, **cookie_match)
Esempio n. 7
0
    def _add_dns_passthrough_flows(self, sid, mac_addr):
        parser = self._datapath.ofproto_parser
        # Set so packet skips enforcement and send to egress
        action = load_passthrough(parser)

        # Install UDP flows for DNS
        ulink_match_udp = MagmaMatch(eth_type=ether_types.ETH_TYPE_IP,
                                     ip_proto=IPPROTO_UDP,
                                     udp_dst=53,
                                     eth_src=mac_addr)
        self._add_resubmit_flow(sid, ulink_match_udp, action,
                                flows.PASSTHROUGH_PRIORITY)

        dlink_match_udp = MagmaMatch(eth_type=ether_types.ETH_TYPE_IP,
                                     ip_proto=IPPROTO_UDP,
                                     udp_src=53,
                                     eth_dst=mac_addr)
        self._add_resubmit_flow(sid, dlink_match_udp, action,
                                flows.PASSTHROUGH_PRIORITY)

        # Install TCP flows for DNS
        ulink_match_tcp = MagmaMatch(eth_type=ether_types.ETH_TYPE_IP,
                                     ip_proto=IPPROTO_TCP,
                                     tcp_dst=53,
                                     eth_src=mac_addr)
        self._add_resubmit_flow(sid, ulink_match_tcp, action,
                                flows.PASSTHROUGH_PRIORITY)

        dlink_match_tcp = MagmaMatch(eth_type=ether_types.ETH_TYPE_IP,
                                     ip_proto=IPPROTO_TCP,
                                     tcp_src=53,
                                     eth_dst=mac_addr)
        self._add_resubmit_flow(sid, dlink_match_tcp, action,
                                flows.PASSTHROUGH_PRIORITY)

        # Install TCP flows for DNS over tls
        ulink_match_tcp = MagmaMatch(eth_type=ether_types.ETH_TYPE_IP,
                                     ip_proto=IPPROTO_TCP,
                                     tcp_dst=853,
                                     eth_src=mac_addr)
        self._add_resubmit_flow(sid, ulink_match_tcp, action,
                                flows.PASSTHROUGH_PRIORITY)

        dlink_match_tcp = MagmaMatch(eth_type=ether_types.ETH_TYPE_IP,
                                     ip_proto=IPPROTO_TCP,
                                     tcp_src=853,
                                     eth_dst=mac_addr)
        self._add_resubmit_flow(sid, dlink_match_tcp, action,
                                flows.PASSTHROUGH_PRIORITY)
Esempio n. 8
0
    def _install_downlink_arp_flows(
        self, priority: int, in_port: int,
        ue_ip_adr: IPAddress, sid: int,
    ):

        parser = self._datapath.ofproto_parser
        match = MagmaMatch(
            eth_type=ether_types.ETH_TYPE_ARP,
            in_port=in_port,
            arp_tpa=ipaddress.IPv4Address(ue_ip_adr.address.decode('utf-8')),
        )
        actions = []
        if sid:
            actions = [parser.OFPActionSetField(metadata=sid)]

        flows.add_resubmit_next_service_flow(
            self._datapath, self.tbl_num, match,
            actions=actions, priority=priority,
            reset_default_register=False,
            resubmit_table=self.next_table,
        )
Esempio n. 9
0
 def _remove_extra_flows(self, extra_flows):
     msg_list = []
     for flow in extra_flows:
         if DIRECTION_REG in flow.match:
             direction = Direction(flow.match.get(DIRECTION_REG, None))
         else:
             direction = None
         match = MagmaMatch(imsi=flow.match.get(IMSI_REG, None),
                            direction=direction)
         self.logger.debug('Sending msg for deletion -> %s',
                           flow.match.get('reg1', None))
         msg_list.append(
             flows.get_delete_flow_msg(
                 self._datapath,
                 self.tbl_num,
                 match,
                 cookie=flow.cookie,
                 cookie_mask=flows.OVS_COOKIE_MATCH_ALL))
     if msg_list:
         chan = self._msg_hub.send(msg_list, self._datapath)
         self._wait_for_responses(chan, len(msg_list))
Esempio n. 10
0
    def install_drop_flows(self):
        """
        Install flows that send test-packets to the controller instead of
        dropping them if no match is found
        """
        drop_tables = set()
        for tables in self._service_manager \
                .get_all_table_assignments() \
                .values():
            drop_tables.update(tables.scratch_tables + [tables.main_table])

        drop_tables.discard(0)
        drop_tables = drop_tables.difference(self.drop_flows_installed)
        for table in drop_tables:
            self.logger.debug('Installing drop flow for %d', table)
            flows.add_trace_packet_output_flow(datapath=self._datapath,
                                               table=table,
                                               match=MagmaMatch(),
                                               instructions=[],
                                               priority=MINIMUM_PRIORITY)
            self.drop_flows_installed.add(table)
Esempio n. 11
0
    def _deactivate_flow_for_rule(self, imsi, ip_addr, rule_id):
        """
        Deactivate a specific rule using the flow cookie for a subscriber

        Args:
            imsi (string): subscriber id
            rule_id (string): policy rule id
        """
        try:
            num = self._rule_mapper.get_rule_num(rule_id)
        except KeyError:
            self.logger.error('Could not find rule id %s', rule_id)
            return
        cookie, mask = (num, flows.OVS_COOKIE_MATCH_ALL)
        match = MagmaMatch(imsi=encode_imsi(imsi))
        flows.delete_flow(self._datapath, self.tbl_num, match,
                          cookie=cookie, cookie_mask=mask)
        self._redirect_manager.deactivate_flow_for_rule(self._datapath, imsi,
                                                        num)
        self._qos_mgr.remove_subscriber_qos(imsi, num)
        self._remove_he_flows(ip_addr, rule_id)
Esempio n. 12
0
    def _install_allow_incoming_arp_flow(self, datapath):
        """
        Install a flow rule to allow any ARP packets coming from the UPLINK,
        this will be hit if arp clamping doesn't recognize the address
        """
        parser = datapath.ofproto_parser
        match = MagmaMatch(
            eth_type=ether_types.ETH_TYPE_ARP,
            direction=Direction.IN,
        )
        # Set so packet skips enforcement and send to egress
        actions = [load_passthrough(parser)]

        flows.add_resubmit_next_service_flow(
            datapath,
            self.table_num,
            match,
            actions=actions,
            priority=flows.UE_FLOW_PRIORITY - 1,
            resubmit_table=self.next_table,
        )
Esempio n. 13
0
    def _set_outgoing_arp_flows(self, datapath, ip_block):
        """
        Install a flow rule to allow any ARP packets coming from the UE
        """
        parser = datapath.ofproto_parser
        match = MagmaMatch(
            eth_type=ether_types.ETH_TYPE_ARP,
            direction=Direction.OUT,
            arp_spa=ip_block,
        )
        # Set so packet skips enforcement and send to egress
        actions = [load_passthrough(parser)]

        flows.add_resubmit_next_service_flow(
            datapath,
            self.table_num,
            match,
            actions=actions,
            priority=flows.UE_FLOW_PRIORITY,
            resubmit_table=self.next_table,
        )
Esempio n. 14
0
    def _add_output_flow(
        self,
        local_f_teid: int,
        ue_ip_addr: IPAddress,
        output_port: int,
        max_len: int,
        actions,
    ):

        ip_match_out = get_ue_ip_match_args(ue_ip_addr, Direction.IN)
        match = MagmaMatch(eth_type=get_eth_type(ue_ip_addr), **ip_match_out)

        flows.add_output_flow(
            self._datapath,
            self.tbl_num,
            match=match,
            actions=actions,
            priority=Utils.PAGING_RULE_PRIORITY,
            cookie=local_f_teid,
            output_port=output_port,
            max_len=max_len,
        )
Esempio n. 15
0
File: arp.py Progetto: sdechi/magma
    def set_incoming_arp_flows_req(self, datapath, ip_block, src_mac,
                                   flow_priority: int = flows.UE_FLOW_PRIORITY):
        parser = datapath.ofproto_parser
        ofproto = datapath.ofproto

        # Set up ARP responder using flow rules. Add a rule with the following
        # 1. eth_dst becomes eth_src (back to sender)
        # 2. eth_src becomes the bridge MAC
        # 3. Set ARP op field to reply
        # 4. Target MAC becomes source MAC
        # 5. Source MAC becomes bridge MAC
        # 6. Swap target and source IPs using register 0 as a buffer
        # 7. Send back to the port the packet came on
        arp_req_match = MagmaMatch(eth_type=ether_types.ETH_TYPE_ARP,
                                   direction=Direction.IN,
                                   arp_op=arp.ARP_REQUEST, arp_tpa=ip_block)
        actions = [
            parser.NXActionRegMove(src_field='eth_src',
                                   dst_field='eth_dst',
                                   n_bits=48),
            parser.OFPActionSetField(eth_src=src_mac),
            parser.OFPActionSetField(arp_op=arp.ARP_REPLY),
            parser.NXActionRegMove(src_field='arp_sha',
                                   dst_field='arp_tha',
                                   n_bits=48),
            parser.OFPActionSetField(arp_sha=src_mac),
            parser.NXActionRegMove(src_field='arp_tpa',
                                   dst_field='reg0',
                                   n_bits=32),
            parser.NXActionRegMove(src_field='arp_spa',
                                   dst_field='arp_tpa',
                                   n_bits=32),
            parser.NXActionRegMove(src_field='reg0',
                                   dst_field='arp_spa',
                                   n_bits=32),
        ]
        flows.add_output_flow(datapath, self.table_num, arp_req_match, actions,
                              priority=flow_priority,
                              output_port=ofproto.OFPP_IN_PORT)
Esempio n. 16
0
    def classify_flow(self, match, app):
        ryu_match = {'eth_type': ether_types.ETH_TYPE_IP}

        ryu_match['ipv4_dst'] = self._get_ip_tuple(match.ipv4_dst)
        ryu_match['ipv4_src'] = self._get_ip_tuple(match.ipv4_src)
        ryu_match['ip_proto'] = match.ip_proto
        if match.ip_proto == match.IPProto.IPPROTO_TCP:
            ryu_match['tcp_dst'] = match.tcp_dst
            ryu_match['tcp_src'] = match.tcp_src
        elif match.ip_proto == match.IPProto.IPPROTO_UDP:
            ryu_match['udp_dst'] = match.udp_dst
            ryu_match['udp_src'] = match.udp_src

        parser = self._datapath.ofproto_parser
        app_id = appMap.get(app, 1)  # 1 is returned for unknown apps
        actions = [parser.NXActionRegLoad2(dst='reg3', value=app_id)]

        flows.add_resubmit_next_service_flow(self._datapath, self.tbl_num,
                                             MagmaMatch(**ryu_match), actions,
                                             priority=flows.DEFAULT_PRIORITY,
                                             resubmit_table=self.next_table)
        return True
Esempio n. 17
0
    def _install_paging_flow(self, ue_ip_addr:IPAddress, local_f_teid:int,
                             ng_flag: bool = True):

        ofproto = self._datapath.ofproto
        parser = self._datapath.ofproto_parser
        ip_match_out = get_ue_ip_match_args(ue_ip_addr, Direction.IN)
        match = MagmaMatch(eth_type=get_eth_type(ue_ip_addr), **ip_match_out)

        # Pass Controller ID value as a ACTION
        classifier_controller_id = 0
        if ng_flag:
            classifier_controller_id = self.config.classifier_controller_id

        actions = [parser.NXActionController(0, classifier_controller_id,
                                             ofproto.OFPR_ACTION_SET)]

        flows.add_output_flow(self._datapath, self.tbl_num,
                              match=match, actions=actions,
                              priority=Utils.PAGING_RULE_PRIORITY,
                              cookie=local_f_teid,
                              output_port=ofproto.OFPP_CONTROLLER,
                              max_len=ofproto.OFPCML_NO_BUFFER)
Esempio n. 18
0
 def _add_resubmit_next_service_flow(
     self,
     ue_ip_adr: IPAddress,
     in_port: int,
     priority: int,
     actions,
 ):
     ip_match_out = get_ue_ip_match_args(ue_ip_adr, Direction.IN)
     match = MagmaMatch(
         eth_type=get_eth_type(ue_ip_adr),
         in_port=in_port,
         **ip_match_out,
     )
     flows.add_resubmit_next_service_flow(
         self._datapath,
         self.tbl_num,
         match,
         actions=actions,
         priority=priority,
         reset_default_register=False,
         resubmit_table=self.next_table,
     )
Esempio n. 19
0
    def _install_uplink_s8_tunnel_flows(self, priority: int, i_teid: int,
                                        o_teid: int, pgw_ip_addr: str,
                                        gtp_portno: int, sid: int,
                                        pgw_gtp_port: int):

        parser = self._datapath.ofproto_parser
        match = MagmaMatch(tunnel_id=i_teid, in_port=gtp_portno)
        gtp_port = pgw_gtp_port
        if pgw_gtp_port == 0:
            gtp_port = self.config.gtp_port

        actions = [parser.OFPActionSetField(tunnel_id=o_teid),
                   parser.OFPActionSetField(tun_ipv4_dst=pgw_ip_addr),
                   parser.NXActionRegLoad2(dst=TUN_PORT_REG, value=gtp_port),
                   parser.OFPActionSetField(eth_dst="ff:ff:ff:ff:ff:ff")]

        if sid:
            actions.append(parser.OFPActionSetField(metadata=sid))

        flows.add_resubmit_next_service_flow(self._datapath, self.tbl_num, match,
                                             actions=actions, priority=priority,
                                             reset_default_register=False,
                                             resubmit_table=self.next_table)
Esempio n. 20
0
    def _install_default_flows_if_not_installed(self, datapath,
            existing_flows: List[OFPFlowStats]) -> List[OFPFlowStats]:
        """
        Install default flows(if not already installed) to forward the traffic,
        If no other flows are matched.

        Returns:
            The list of flows that remain after inserting default flows
        """
        match = MagmaMatch()
        msg = flows.get_add_drop_flow_msg(
            datapath, self.tbl_num, match,
            priority=flows.MINIMUM_PRIORITY,
            cookie=self.DEFAULT_FLOW_COOKIE)

        msg, remaining_flows = self._msg_hub \
            .filter_msgs_if_not_in_flow_list(self._datapath, [msg],
                                             existing_flows[self.tbl_num])
        if msg:
            chan = self._msg_hub.send(msg, datapath)
            self._wait_for_responses(chan, 1)

        return {self.tbl_num: remaining_flows}
Esempio n. 21
0
    def _install_downlink_tunnel_flows(self, priority: int, i_teid: int,
                                       o_teid: int, in_port: int,
                                       ue_ip_adr:IPAddress, enodeb_ip_addr:str,
                                       gtp_portno: int, sid: int, ng_flag: bool):

        parser = self._datapath.ofproto_parser
        ip_match_out = get_ue_ip_match_args(ue_ip_adr, Direction.IN)
        match = MagmaMatch(eth_type=get_eth_type(ue_ip_adr),
                           in_port=in_port, **ip_match_out)

        actions = [parser.OFPActionSetField(tunnel_id=o_teid),
                   parser.OFPActionSetField(tun_ipv4_dst=enodeb_ip_addr),
                   parser.NXActionRegLoad2(dst=TUN_PORT_REG, value=gtp_portno)]
        if ng_flag:
            actions.append(parser.OFPActionSetField(tun_flags=TUNNEL_OAM_FLAG))
        if i_teid:
            actions.append(parser.NXActionRegLoad2(dst=INGRESS_TUN_ID_REG, value=i_teid))
        if sid:
            actions.append(parser.OFPActionSetField(metadata=sid))

        flows.add_resubmit_next_service_flow(self._datapath, self.tbl_num, match,
                                             actions=actions, priority=priority,
                                             reset_default_register=False,
                                             resubmit_table=self.next_table)
Esempio n. 22
0
    def _install_set_vlan_id_flows(self, dp):
        parser = self._datapath.ofproto_parser

        # Load VLAN header (needs to be done before settubg vlan tag)
        # Can't be done through the learn action because ryu doesn't support it
        match = MagmaMatch(
            direction=Direction.IN,
            vlan_tag=self.LOAD_VLAN,
        )
        actions = [
            parser.OFPActionPushVlan(ether.ETH_TYPE_8021Q),
            parser.NXActionRegLoad2(
                dst=VLAN_TAG_REG,
                value=0,
            ),
        ]
        flows.add_resubmit_next_service_flow(
            dp,
            self.vlan_id_scratch,
            match,
            actions,
            priority=flows.UE_FLOW_PRIORITY,
            resubmit_table=self.vlan_id_scratch,
        )
Esempio n. 23
0
    def _install_default_ingress_flows(self, dp):
        """
        Sets up the ingress table, the first step in the packet processing
        pipeline.

        This sets up flow rules to annotate packets with a metadata bit
        indicating the direction. Incoming packets are defined as packets
        originating from the LOCAL port, outgoing packets are defined as
        packets originating from the gtp port.

        All other packets bypass the pipeline.

        Note that the ingress rules do *not* install any flows that cause
        PacketIns (i.e., sends packets to the controller).

        Raises:
            MagmaOFError if any of the default flows fail to install.
        """
        parser = dp.ofproto_parser
        next_table = self._service_manager.get_next_table_num(INGRESS)

        # set traffic direction bits
        # set a direction bit for outgoing (pn -> inet) traffic.
        match = MagmaMatch(in_port=self.config.gtp_port)
        actions = [load_direction(parser, Direction.OUT)]
        flows.add_resubmit_next_service_flow(dp,
                                             self._ingress_tbl_num,
                                             match,
                                             actions=actions,
                                             priority=flows.DEFAULT_PRIORITY,
                                             resubmit_table=next_table)

        # set a direction bit for incoming (internet -> UE) traffic.
        match = MagmaMatch(in_port=OFPP_LOCAL)
        actions = [load_direction(parser, Direction.IN)]
        flows.add_resubmit_next_service_flow(dp,
                                             self._ingress_tbl_num,
                                             match,
                                             actions=actions,
                                             priority=flows.DEFAULT_PRIORITY,
                                             resubmit_table=next_table)

        # set a direction bit for incoming (internet -> UE) traffic.
        match = MagmaMatch(in_port=self._uplink_port)
        actions = [load_direction(parser, Direction.IN)]
        flows.add_resubmit_next_service_flow(dp,
                                             self._ingress_tbl_num,
                                             match,
                                             actions=actions,
                                             priority=flows.DEFAULT_PRIORITY,
                                             resubmit_table=next_table)

        # Send RADIUS requests directly to li table
        if self._li_port:
            match = MagmaMatch(in_port=self._li_port)
            actions = [load_direction(parser, Direction.IN)]
            flows.add_resubmit_next_service_flow(
                dp,
                self._ingress_tbl_num,
                match,
                actions=actions,
                priority=flows.DEFAULT_PRIORITY,
                resubmit_table=self._li_table)

        # set a direction bit for incoming (mtr -> UE) traffic.
        if self._mtr_service_enabled:
            match = MagmaMatch(in_port=self.config.mtr_port)
            actions = [load_direction(parser, Direction.IN)]
            flows.add_resubmit_next_service_flow(
                dp,
                self._ingress_tbl_num,
                match,
                actions=actions,
                priority=flows.DEFAULT_PRIORITY,
                resubmit_table=next_table)
Esempio n. 24
0
    def test_rule_reactivation(self):
        """
        Adds a policy to a subscriber, deletes it by incrementing the
        version, and add it back. Verifies that the usage stats is correctly
        reported, the old flows are deleted, and the new flows are installed.

        Assert:
            UPLINK policy matches 128 packets (*34 = 4352 bytes)
            Old flows are deleted
            New flows are installed
            No other stats are reported
        """
        fake_controller_setup(self.enforcement_controller,
                              self.enforcement_stats_controller)
        imsi = 'IMSI001010000000013'
        sub_ip = '192.168.128.74'
        num_pkts_tx_match = 128

        flow_list = [
            FlowDescription(match=FlowMatch(ipv4_dst='45.10.0.0/25',
                                            direction=FlowMatch.UPLINK),
                            action=FlowDescription.PERMIT)
        ]
        policy = PolicyRule(id='rule1', priority=3, flow_list=flow_list)
        enf_stat_name = imsi + '|rule1'
        self.service_manager.session_rule_version_mapper.update_version(
            imsi, 'rule1')
        version = \
            self.service_manager.session_rule_version_mapper.get_version(
                imsi, 'rule1')
        """ Setup subscriber, setup table_isolation to fwd pkts """
        self._static_rule_dict[policy.id] = policy
        sub_context = RyuDirectSubscriberContext(
            imsi, sub_ip, self.enforcement_controller, self._main_tbl_num,
            self.enforcement_stats_controller).add_static_rule(policy.id)
        isolator = RyuDirectTableIsolator(
            RyuForwardFlowArgsBuilder.from_subscriber(
                sub_context.cfg).build_requests(), self.testing_controller)
        """ Create a packet """
        pkt_sender = ScapyPacketInjector(self.IFACE)
        packet = IPPacketBuilder() \
            .set_ip_layer('45.10.0.0/20', sub_ip) \
            .set_ether_layer(self.MAC_DEST, "00:00:00:00:00:00") \
            .build()

        # =========================== Verification ===========================
        rule_num = self.enforcement_stats_controller._rule_mapper \
            .get_or_create_rule_num(policy.id)
        enf_query = FlowQuery(self._main_tbl_num,
                              self.testing_controller,
                              match=flow_match_to_magma_match(
                                  FlowMatch(ipv4_dst='45.10.0.0/25',
                                            direction=FlowMatch.UPLINK)),
                              cookie=rule_num)
        es_old_version_query = FlowQuery(self._scratch_tbl_num,
                                         self.testing_controller,
                                         match=MagmaMatch(
                                             imsi=encode_imsi(imsi),
                                             reg2=rule_num,
                                             rule_version=version),
                                         cookie=rule_num)
        es_new_version_query = FlowQuery(self._scratch_tbl_num,
                                         self.testing_controller,
                                         match=MagmaMatch(
                                             imsi=encode_imsi(imsi),
                                             reg2=rule_num,
                                             rule_version=version + 1),
                                         cookie=rule_num)
        packet_wait = FlowVerifier([], self._wait_func([enf_stat_name]))
        """ Verify that flows are properly deleted """
        verifier = FlowVerifier([
            FlowTest(es_old_version_query, 0, flow_count=0),
            FlowTest(es_new_version_query, num_pkts_tx_match, flow_count=2),
            FlowTest(enf_query, num_pkts_tx_match, flow_count=1),
        ], self._wait_func([enf_stat_name]))
        snapshot_verifier = SnapshotVerifier(self, self.BRIDGE,
                                             self.service_manager)
        """
        Send a packet, then deactivate and reactivate the same rule and send a
        packet. Wait until it is received by ovs and enf stats.
        """
        with isolator, sub_context, verifier, snapshot_verifier:
            with packet_wait:
                self.enforcement_stats_controller._report_usage.reset_mock()
                pkt_sender.send(packet)

            self.enforcement_stats_controller._report_usage.reset_mock()
            self.service_manager.session_rule_version_mapper. \
                update_version(imsi, 'rule1')
            self.enforcement_controller.deactivate_rules(imsi, [policy.id])
            self.enforcement_controller.activate_rules(imsi, sub_ip,
                                                       [policy.id], [])
            self.enforcement_stats_controller.activate_rules(
                imsi, sub_ip, [policy.id], [])
            pkt_sender.send(packet)

        verifier.verify()

        stats = get_enforcement_stats(
            self.enforcement_stats_controller._report_usage.call_args_list)
        """
        Verify both packets are reported after reactivation.
        """
        self.assertEqual(stats[enf_stat_name].sid, imsi)
        self.assertEqual(stats[enf_stat_name].rule_id, "rule1")
        self.assertEqual(stats[enf_stat_name].bytes_rx, 0)
        # TODO Figure out why this one fails.
        #self.assertEqual(stats[enf_stat_name].bytes_tx,
        #                 num_pkts_tx_match * len(packet))
        self.assertEqual(len(stats), 1)
Esempio n. 25
0
    def test_passthrough_rules(self):
        """
           Add UE MAC flows for two subscribers
        """
        imsi_1 = 'IMSI010000000088888'
        other_mac = '5e:cc:cc:b1:aa:aa'
        cli_ip = '1.1.1.1'
        server_ip = '151.42.41.122'

        # Add subscriber with UE MAC address """
        self.ue_mac_controller.add_ue_mac_flow(imsi_1, self.UE_MAC_1)

        # Create a set of packets
        pkt_sender = ScapyPacketInjector(self.BRIDGE)

        # Only send downlink as the pkt_sender sends pkts from in_port=LOCAL
        downlink_packet1 = EtherPacketBuilder() \
            .set_ether_layer(self.UE_MAC_1, other_mac) \
            .build()
        dhcp_packet = DHCPPacketBuilder() \
            .set_ether_layer(self.UE_MAC_1, other_mac) \
            .set_ip_layer(server_ip, cli_ip) \
            .set_udp_layer(67, 68) \
            .set_bootp_layer(2, cli_ip, server_ip, other_mac) \
            .set_dhcp_layer([("message-type", "ack"), "end"]) \
            .build()
        dns_packet = UDPPacketBuilder() \
            .set_ether_layer(self.UE_MAC_1, other_mac) \
            .set_ip_layer('151.42.41.122', '1.1.1.1') \
            .set_udp_layer(53, 32795) \
            .build()
        arp_packet = ARPPacketBuilder() \
            .set_ether_layer(self.UE_MAC_1, other_mac) \
            .set_arp_layer('1.1.1.1') \
            .set_arp_hwdst(self.UE_MAC_1) \
            .set_arp_src(other_mac, '1.1.1.12') \
            .build()

        # Check if these flows were added (queries should return flows)
        flow_queries = [
            FlowQuery(self._tbl_num, self.testing_controller,
                      match=MagmaMatch(eth_dst=self.UE_MAC_1))
        ]

        # =========================== Verification ===========================
        # Verify 3 flows installed for ue_mac table (3 pkts matched)
        #        4 flows installed for inout (3 pkts matched)
        #        2 flows installed (2 pkts matches)
        flow_verifier = FlowVerifier(
            [
                FlowTest(FlowQuery(self._tbl_num,
                                   self.testing_controller), 4, 3),
                FlowTest(FlowQuery(self._ingress_tbl_num,
                                   self.testing_controller), 4, 2),
                FlowTest(FlowQuery(self._egress_tbl_num,
                                   self.testing_controller), 3, 2),
                FlowTest(flow_queries[0], 4, 1),
            ], lambda: wait_after_send(self.testing_controller))

        snapshot_verifier = SnapshotVerifier(self, self.BRIDGE,
                                             self.service_manager)

        with flow_verifier, snapshot_verifier:
            pkt_sender.send(dhcp_packet)
            pkt_sender.send(downlink_packet1)
            pkt_sender.send(dns_packet)
            hub.sleep(3)
            pkt_sender.send(arp_packet)

        flow_verifier.verify()
Esempio n. 26
0
 def _remove_mirror_flows(self, imsis):
     for imsi in imsis:
         self.logger.error("Disabling LI tracking for IMSI  %s", imsi)
         match = MagmaMatch(imsi=encode_imsi(imsi))
         flows.delete_flow(self._datapath, self.tbl_num, match)
Esempio n. 27
0
    def add_tunnel_flows(self,
                         precedence: int,
                         i_teid: int,
                         o_teid: int,
                         ue_ip_adr: IPAddress,
                         enodeb_ip_addr: str,
                         sid: int = None) -> bool:

        parser = self._datapath.ofproto_parser
        priority = Utils.get_of_priority(precedence)
        # Add flow for gtp port
        if enodeb_ip_addr:
            gtp_portno = self._add_gtp_port(enodeb_ip_addr)
        else:
            gtp_portno = self.config.gtp_port

        # Add flow for gtp port for Uplink Tunnel
        actions = []
        if i_teid:
            match = MagmaMatch(tunnel_id=i_teid, in_port=gtp_portno)

            actions = [
                parser.OFPActionSetField(eth_src=GTP_PORT_MAC),
                parser.OFPActionSetField(eth_dst="ff:ff:ff:ff:ff:ff")
            ]
            if sid:
                actions.append(parser.OFPActionSetField(metadata=sid))

            flows.add_resubmit_next_service_flow(
                self._datapath,
                self.tbl_num,
                match,
                actions=actions,
                priority=priority,
                reset_default_register=False,
                resubmit_table=self.next_table)

        # Install Downlink Tunnel
        actions = []
        if not ue_ip_adr:
            self.logger.error("ue_ip_address is None")
            return
        else:
            # Add flow for LOCAL port
            ip_match_out = get_ue_ip_match_args(ue_ip_adr, Direction.IN)
            match = MagmaMatch(eth_type=get_eth_type(ue_ip_adr),
                               in_port=self._uplink_port,
                               **ip_match_out)
            if o_teid and enodeb_ip_addr:

                actions = [
                    parser.OFPActionSetField(tunnel_id=o_teid),
                    parser.OFPActionSetField(tun_ipv4_dst=enodeb_ip_addr),
                    parser.OFPActionSetField(tun_flags=TUNNEL_OAM_FLAG),
                    parser.NXActionRegLoad2(dst=TUN_PORT_REG, value=gtp_portno)
                ]
                if sid:
                    actions.append(parser.OFPActionSetField(metadata=sid))

                flows.add_resubmit_next_service_flow(
                    self._datapath,
                    self.tbl_num,
                    match,
                    actions=actions,
                    priority=priority,
                    reset_default_register=False,
                    resubmit_table=self.next_table)

            # Add flow for mtr port
            match = MagmaMatch(eth_type=get_eth_type(ue_ip_adr),
                               in_port=self.config.mtr_port,
                               **ip_match_out)

            flows.add_resubmit_next_service_flow(
                self._datapath,
                self.tbl_num,
                match,
                actions=actions,
                priority=priority,
                reset_default_register=False,
                resubmit_table=self.next_table)

            # Add ARP flow for LOCAL port
            if ue_ip_adr.version == IPAddress.IPV4:
                match = MagmaMatch(eth_type=ether_types.ETH_TYPE_ARP,
                                   in_port=self._uplink_port,
                                   arp_tpa=ipaddress.IPv4Address(
                                       ue_ip_adr.address.decode('utf-8')))
            actions = []
            if sid:
                actions = [parser.OFPActionSetField(metadata=sid)]

            flows.add_resubmit_next_service_flow(
                self._datapath,
                self.tbl_num,
                match,
                actions=actions,
                priority=priority,
                reset_default_register=False,
                resubmit_table=self.next_table)

            # Add ARP flow for mtr port
            if ue_ip_adr.version == IPAddress.IPV4:
                match = MagmaMatch(eth_type=ether_types.ETH_TYPE_ARP,
                                   in_port=self.config.mtr_port,
                                   arp_tpa=ipaddress.IPv4Address(
                                       ue_ip_adr.address.decode('utf-8')))

            flows.add_resubmit_next_service_flow(
                self._datapath,
                self.tbl_num,
                match,
                actions=actions,
                priority=priority,
                reset_default_register=False,
                resubmit_table=self.next_table)

        return True
Esempio n. 28
0
 def _add_uplink_arp_allow_flow(self):
     arp_match = MagmaMatch(eth_type=ether_types.ETH_TYPE_ARP)
     flows.add_resubmit_next_service_flow(self._datapath, self.tbl_num,
                                          arp_match, actions=[],
                                          priority=flows.DEFAULT_PRIORITY,
                                          resubmit_table=self.next_table)
Esempio n. 29
0
    def _delete_uplink_tunnel_flows(self, i_teid: int, gtp_portno: int):

        match = MagmaMatch(tunnel_id=i_teid, in_port=gtp_portno)

        flows.delete_flow(self._datapath, self.tbl_num, match)
Esempio n. 30
0
    def _install_default_egress_flows(self,
                                      dp,
                                      mac_addr: str = "",
                                      vlan: str = ""):
        """
        Egress table is the last table that a packet touches in the pipeline.
        Output downlink traffic to gtp port, uplink trafic to LOCAL
        Args:
            mac_addr: In Non NAT mode, this is upstream internet GW mac address
            vlan: in multi APN this is vlan_id of the upstream network.

        Raises:
            MagmaOFError if any of the default flows fail to install.
        """

        if self.config.setup_type == 'LTE':
            _install_vlan_egress_flows(dp, self._egress_tbl_num, "0.0.0.0/0")
            self._install_proxy_flows(dp)
        else:
            # Use regular match for Non LTE setup.
            downlink_match = MagmaMatch(direction=Direction.IN)
            flows.add_output_flow(dp,
                                  self._egress_tbl_num,
                                  downlink_match, [],
                                  output_port=self.config.gtp_port)

        if vlan != "":
            vid = 0x1000 | int(vlan)
            uplink_match = MagmaMatch(direction=Direction.OUT,
                                      vlan_vid=(vid, vid))
        else:
            uplink_match = MagmaMatch(direction=Direction.OUT)

        actions = []
        # avoid resetting mac address on switch connect event.
        if mac_addr == "":
            mac_addr = self._current_upstream_mac_map.get(vlan, "")
        if mac_addr == "" and self.config.enable_nat is False and \
            self.config.setup_type == 'LTE':
            mac_addr = self.config.uplink_gw_mac

        if mac_addr != "":
            parser = dp.ofproto_parser
            actions.append(
                parser.NXActionRegLoad2(dst='eth_dst', value=mac_addr))
            if self._current_upstream_mac_map.get(vlan, "") != mac_addr:
                self.logger.info("Using GW: mac: %s match %s actions: %s",
                                 mac_addr, str(uplink_match.ryu_match),
                                 str(actions))

                self._current_upstream_mac_map[vlan] = mac_addr

        if vlan != "":
            priority = flows.UE_FLOW_PRIORITY
        elif mac_addr != "":
            priority = flows.DEFAULT_PRIORITY
        else:
            priority = flows.MINIMUM_PRIORITY

        flows.add_output_flow(dp,
                              self._egress_tbl_num,
                              uplink_match,
                              priority=priority,
                              actions=actions,
                              output_port=self.config.uplink_port)