def _add_dhcp_passthrough_flows(self): ofproto, parser = self._datapath.ofproto, self._datapath.ofproto_parser # Set so packet skips enforcement controller action = load_passthrough(parser) uplink_match = MagmaMatch(eth_type=ether_types.ETH_TYPE_IP, ip_proto=IPPROTO_UDP, udp_src=68, udp_dst=67) self._add_resubmit_flow(None, uplink_match, action, flows.PASSTHROUGH_PRIORITY, tbl_num=self._passthrough_set_tbl) downlink_match = MagmaMatch(eth_type=ether_types.ETH_TYPE_IP, ip_proto=IPPROTO_UDP, udp_src=67, udp_dst=68) # Set so triggers packetin and we can learn the ip to do arp response self._add_resubmit_flow(None, downlink_match, action, flows.PASSTHROUGH_PRIORITY, next_table=self._dhcp_learn_scratch, tbl_num=self._passthrough_set_tbl) # Install default flow for dhcp learn scratch flows.add_output_flow(self._datapath, self._dhcp_learn_scratch, match=MagmaMatch(), actions=[], priority=flows.PASSTHROUGH_PRIORITY, output_port=ofproto.OFPP_CONTROLLER, copy_table=self.next_table, max_len=ofproto.OFPCML_NO_BUFFER)
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)
def _delete_dns_passthrough_flows(self, sid, mac_addr): parser = self._datapath.ofproto_parser # Set so packet skips enforcement controller 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._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 set_incoming_arp_flows_res( self, datapath, ip_block, flow_priority: int = flows.UE_FLOW_PRIORITY, ): parser = datapath.ofproto_parser arp_resp_match = MagmaMatch( eth_type=ether_types.ETH_TYPE_ARP, direction=Direction.IN, arp_op=arp.ARP_REPLY, arp_tpa=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, arp_resp_match, actions=actions, priority=flow_priority, resubmit_table=self.next_table, )
def set_incoming_arp_flows(self, datapath, ip_block, src_mac, flow_priority: int = flows.UE_FLOW_PRIORITY): """ Install flow rules for incoming ARPs(to UE): - For ARP request: respond to incoming ARP requests. - For ARP response: pass to next table. """ parser = datapath.ofproto_parser ofproto = datapath.ofproto arp_resp_match = MagmaMatch(eth_type=ether_types.ETH_TYPE_ARP, direction=Direction.IN, arp_op=arp.ARP_REPLY, arp_tpa=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, arp_resp_match, actions=actions, priority=flow_priority, resubmit_table=self.next_table) # 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)
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)
def _add_dns_passthrough_flows(self): 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) self._add_resubmit_flow(None, ulink_match_udp, action, flows.PASSTHROUGH_PRIORITY, tbl_num=self._passthrough_set_tbl) dlink_match_udp = MagmaMatch(eth_type=ether_types.ETH_TYPE_IP, ip_proto=IPPROTO_UDP, udp_src=53) self._add_resubmit_flow(None, dlink_match_udp, action, flows.PASSTHROUGH_PRIORITY, tbl_num=self._passthrough_set_tbl) # Install TCP flows for DNS ulink_match_tcp = MagmaMatch(eth_type=ether_types.ETH_TYPE_IP, ip_proto=IPPROTO_TCP, tcp_dst=53) self._add_resubmit_flow(None, ulink_match_tcp, action, flows.PASSTHROUGH_PRIORITY, tbl_num=self._passthrough_set_tbl) dlink_match_tcp = MagmaMatch(eth_type=ether_types.ETH_TYPE_IP, ip_proto=IPPROTO_TCP, tcp_src=53) self._add_resubmit_flow(None, dlink_match_tcp, action, flows.PASSTHROUGH_PRIORITY, tbl_num=self._passthrough_set_tbl) # 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) self._add_resubmit_flow(None, ulink_match_tcp, action, flows.PASSTHROUGH_PRIORITY, tbl_num=self._passthrough_set_tbl) dlink_match_tcp = MagmaMatch(eth_type=ether_types.ETH_TYPE_IP, ip_proto=IPPROTO_TCP, tcp_src=853) self._add_resubmit_flow(None, dlink_match_tcp, action, flows.PASSTHROUGH_PRIORITY, tbl_num=self._passthrough_set_tbl)
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)
def _delete_dhcp_passthrough_flows(self, sid, mac_addr): parser = self._datapath.ofproto_parser # Set so packet skips enforcement controller action = load_passthrough(parser) 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) imsi_match = MagmaMatch(imsi=encode_imsi(sid)) flows.delete_flow(self._datapath, self._dhcp_learn_scratch, imsi_match)
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