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 tbl_num = self._service_manager.get_table_num(INGRESS) 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, 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, 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, tbl_num, match, actions=actions, priority=flows.DEFAULT_PRIORITY, resubmit_table=next_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, tbl_num, match, actions=actions, priority=flows.DEFAULT_PRIORITY, resubmit_table=next_table)
def flow_match_to_actions(datapath, match): ''' Convert a FlowMatch to list of actions to get the same packet Args: match: FlowMatch ''' parser = datapath.ofproto_parser _check_pkt_protocol(match) # Eth type and ip proto are read only, can't set them here (set on pkt init) actions = [ parser.OFPActionSetField( ipv4_src=getattr(match, 'ipv4_src', '1.1.1.1')), parser.OFPActionSetField( ipv4_dst=getattr(match, 'ipv4_dst', '1.2.3.4')), load_direction(parser, get_direction_for_match(match)), parser.NXActionRegLoad2(dst=DPI_REG, value=getattr(match, 'app_id', 0)), ] if match.ip_proto == FlowMatch.IPPROTO_TCP: actions.extend([ parser.OFPActionSetField(tcp_src=getattr(match, 'tcp_src', 0)), parser.OFPActionSetField(tcp_dst=getattr(match, 'tcp_dst', 0)), ]) elif match.ip_proto == FlowMatch.IPPROTO_UDP: actions.extend([ parser.OFPActionSetField(udp_src=getattr(match, 'udp_src', 0)), parser.OFPActionSetField(udp_dst=getattr(match, 'udp_dst', 0)), ]) return actions
def _add_dhcp_passthrough_flows(self, sid, mac_addr): ofproto, parser = self._datapath.ofproto, self._datapath.ofproto_parser # Set so inout knows to skip tables and send to egress action = load_direction(parser, Direction.PASSTHROUGH) uplink_match = MagmaMatch(eth_type=ether_types.ETH_TYPE_IP, ip_proto=IPPROTO_UDP, udp_src=68, udp_dst=67, eth_src=mac_addr) self._add_resubmit_flow(sid, uplink_match, action, flows.PASSTHROUGH_PRIORITY) downlink_match = MagmaMatch(eth_type=ether_types.ETH_TYPE_IP, ip_proto=IPPROTO_UDP, udp_src=67, udp_dst=68, eth_dst=mac_addr) # Set so triggers packetin and we can learn the ip to do arp response self._add_resubmit_flow(sid, downlink_match, action, flows.PASSTHROUGH_PRIORITY, next_table=self._dhcp_learn_scratch) # Install default flow for dhcp learn scratch imsi_match = MagmaMatch(imsi=encode_imsi(sid)) flows.add_output_flow(self._datapath, self._dhcp_learn_scratch, match=imsi_match, actions=[], priority=flows.PASSTHROUGH_PRIORITY, output_port=ofproto.OFPP_CONTROLLER, copy_table=self.next_table, max_len=ofproto.OFPCML_NO_BUFFER)
def _delete_dns_passthrough_flows(self, sid, mac_addr): parser = self._datapath.ofproto_parser # Set so inout knows to skip tables and send to egress action = load_direction(parser, Direction.PASSTHROUGH) # 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._delete_resubmit_flow(sid, ulink_match_udp, action) dlink_match_udp = MagmaMatch(eth_type=ether_types.ETH_TYPE_IP, ip_proto=IPPROTO_UDP, udp_src=53, eth_dst=mac_addr) self._delete_resubmit_flow(sid, dlink_match_udp, action) # 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._delete_resubmit_flow(sid, ulink_match_tcp, action) dlink_match_tcp = MagmaMatch(eth_type=ether_types.ETH_TYPE_IP, ip_proto=IPPROTO_TCP, tcp_src=53, eth_dst=mac_addr) self._delete_resubmit_flow(sid, dlink_match_tcp, action)
def _add_arp_passthrough_flows(self): parser = self._datapath.ofproto_parser next_table = self._service_manager.get_next_table_num(self.APP_NAME) # Set so inout knows to skip tables and send to egress actions = [load_direction(parser, Direction.PASSTHROUGH)] arp_match = MagmaMatch(eth_type=ether_types.ETH_TYPE_ARP) flows.add_resubmit_next_service_flow( self._datapath, self.tbl_num, arp_match, actions=actions, priority=flows.PASSTHROUGH_PRIORITY, resubmit_table=next_table)
def _delete_dhcp_passthrough_flows(self, sid, mac_addr): parser = self._datapath.ofproto_parser # Set so inout knows to skip tables and send to egress action = load_direction(parser, Direction.PASSTHROUGH) uplink_match = MagmaMatch(eth_type=ether_types.ETH_TYPE_IP, ip_proto=IPPROTO_UDP, udp_src=68, udp_dst=67, eth_src=mac_addr) self._delete_resubmit_flow(sid, uplink_match, action) downlink_match = MagmaMatch(eth_type=ether_types.ETH_TYPE_IP, ip_proto=IPPROTO_UDP, udp_src=67, udp_dst=68, eth_dst=mac_addr) self._delete_resubmit_flow(sid, downlink_match, action)
def _get_default_ingress_flow_msgs(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) msgs = [] # set traffic direction bits # set a direction bit for incoming (internet -> UE) traffic. match = MagmaMatch(in_port=OFPP_LOCAL) actions = [load_direction(parser, Direction.IN)] msgs.append( flows.get_add_resubmit_next_service_flow_msg( 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.config.uplink_port) actions = [load_direction(parser, Direction.IN)] msgs.append( flows.get_add_resubmit_next_service_flow_msg( 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)] msgs.append( flows.get_add_resubmit_next_service_flow_msg( 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)] msgs.append( flows.get_add_resubmit_next_service_flow_msg( dp, self._ingress_tbl_num, match, actions=actions, priority=flows.DEFAULT_PRIORITY, resubmit_table=next_table)) if self.config.he_proxy_port != 0: match = MagmaMatch(in_port=self.config.he_proxy_port) actions = [load_direction(parser, Direction.IN)] msgs.append( flows.get_add_resubmit_next_service_flow_msg( dp, self._ingress_tbl_num, match, actions=actions, priority=flows.DEFAULT_PRIORITY, resubmit_table=next_table)) if self.config.setup_type == 'CWF': # set a direction bit for outgoing (pn -> inet) traffic for remaining traffic ps_match_out = MagmaMatch() actions = [load_direction(parser, Direction.OUT)] msgs.append( flows.get_add_resubmit_next_service_flow_msg( dp, self._ingress_tbl_num, ps_match_out, actions=actions, priority=flows.MINIMUM_PRIORITY, resubmit_table=next_table)) else: # set a direction bit for outgoing (pn -> inet) traffic for remaining traffic # Passthrough is zero for packets from eNodeB GTP tunnels ps_match_out = MagmaMatch(passthrough=REG_ZERO_VAL) actions = [load_direction(parser, Direction.OUT)] msgs.append( flows.get_add_resubmit_next_service_flow_msg( dp, self._ingress_tbl_num, ps_match_out, actions=actions, priority=flows.MINIMUM_PRIORITY, resubmit_table=next_table)) # Passthrough is one for packets from remote PGW GTP tunnels, set direction # flag to IN for such packets. ps_match_in = MagmaMatch(passthrough=PASSTHROUGH_REG_VAL) actions = [load_direction(parser, Direction.IN)] msgs.append( flows.get_add_resubmit_next_service_flow_msg( dp, self._ingress_tbl_num, ps_match_in, actions=actions, priority=flows.MINIMUM_PRIORITY, resubmit_table=next_table)) return msgs
def get_subscriber_flows(self, ue_addr: str, uplink_tunnel: int, ip_dst: str, rule_num: int, urls: List[str], imsi: str, msisdn: bytes): """ Add flow to steer traffic to and from proxy port. Args: ue_addr(str): IP address of UE uplink_tunnel(int) Tunnel ID of the session ip_dst(str): HTTP server dst IP (CIDR) rule_num(int): rule num of the policy rule urls(List[str]): list of HTTP server URLs imsi (string): subscriber to install rule for msisdn (bytes): subscriber MSISDN """ if not self.config.he_enabled: return [] dp = self._datapath parser = dp.ofproto_parser try: tunnel_id = int(uplink_tunnel) except ValueError: self.logger.error("parsing tunnel id: [%s], HE might not work in every case", uplink_tunnel) tunnel_id = 0 if urls is None: return [] if ip_dst is None: logging.error("Missing dst ip, ignoring HE rule.") return [] logging.info("Add HE: ue_addr %s, uplink_tunnel %s, ip_dst %s, rule_num %s " "urls %s, imsi %s, msisdn %s", ue_addr, uplink_tunnel, ip_dst, str(rule_num), str(urls), imsi, str(msisdn)) if ip_dst is None or ip_dst == '': ip_dst = '0.0.0.0/0' self.set_he_target_urls(ue_addr, ip_dst, urls, imsi, msisdn) msgs = [] # 1.a. Going to UE: from uplink send to proxy match = MagmaMatch(in_port=self.config.uplink_port, eth_type=ether_types.ETH_TYPE_IP, ipv4_src=ip_dst, ipv4_dst=ue_addr, ip_proto=IPPROTO_TCP, tcp_src=HTTP_PORT, proxy_tag=0) actions = [load_direction(parser, Direction.IN), load_passthrough(parser), set_proxy_tag(parser)] msgs.append( flows.get_add_resubmit_current_service_flow_msg(dp, self.tbl_num, match, cookie=rule_num, actions=actions, priority=flows.DEFAULT_PRIORITY, resubmit_table=self.next_table)) # 1.b. Going to UE: from proxy send to UE match = MagmaMatch(in_port=self.config.he_proxy_port, eth_type=ether_types.ETH_TYPE_IP, ipv4_src=ip_dst, ipv4_dst=ue_addr, ip_proto=IPPROTO_TCP, tcp_src=HTTP_PORT) actions = [set_in_port(parser, self.config.uplink_port), set_proxy_tag(parser)] msgs.append( flows.get_add_resubmit_current_service_flow_msg(dp, self.tbl_num, match, cookie=rule_num, actions=actions, priority=flows.DEFAULT_PRIORITY, resubmit_table=0)) # 1.c. continue (1.b) Going to UE: from proxy send to UE match = MagmaMatch(in_port=self.config.uplink_port, eth_type=ether_types.ETH_TYPE_IP, ipv4_src=ip_dst, ipv4_dst=ue_addr, ip_proto=IPPROTO_TCP, tcp_src=HTTP_PORT, proxy_tag=PROXY_TAG_TO_PROXY) actions = [set_proxy_tag(parser, 0)] msgs.append( flows.get_add_resubmit_current_service_flow_msg(dp, self.tbl_num, match, cookie=rule_num, actions=actions, priority=flows.DEFAULT_PRIORITY, resubmit_table=self.next_table)) # 2.a. To internet from proxy port, send to uplink match = MagmaMatch(in_port=self.config.he_proxy_port, eth_type=ether_types.ETH_TYPE_IP, ipv4_src=ue_addr, ipv4_dst=ip_dst, ip_proto=IPPROTO_TCP, tcp_dst=HTTP_PORT, proxy_tag=0) actions = [set_in_port(parser, self.config.gtp_port), set_tun_id(parser, tunnel_id), set_proxy_tag(parser), load_imsi(parser, imsi)] msgs.append( flows.get_add_resubmit_current_service_flow_msg(dp, self.tbl_num, match, cookie=rule_num, actions=actions, priority=flows.MEDIUM_PRIORITY, resubmit_table=0)) # 2.b. Continue from 2.a -> To internet from proxy port, send to uplink match = MagmaMatch(in_port=self.config.gtp_port, eth_type=ether_types.ETH_TYPE_IP, ipv4_src=ue_addr, ipv4_dst=ip_dst, ip_proto=IPPROTO_TCP, tcp_dst=HTTP_PORT, proxy_tag=PROXY_TAG_TO_PROXY) actions = [set_proxy_tag(parser, 0)] msgs.append( flows.get_add_resubmit_current_service_flow_msg(dp, self.tbl_num, match, cookie=rule_num, actions=actions, priority=flows.DEFAULT_PRIORITY, resubmit_table=self.next_table)) # 2.c. To internet from ue send to proxy, this is coming from HE port match = MagmaMatch(eth_type=ether_types.ETH_TYPE_IP, ipv4_src=ue_addr, ipv4_dst=ip_dst, ip_proto=IPPROTO_TCP, tcp_dst=HTTP_PORT, proxy_tag=0) actions = [load_direction(parser, Direction.OUT), load_passthrough(parser), set_proxy_tag(parser)] msgs.append( flows.get_add_resubmit_current_service_flow_msg(dp, self.tbl_num, match, cookie=rule_num, actions=actions, priority=flows.DEFAULT_PRIORITY, resubmit_table=self.next_table)) return msgs