def _install_ip_blacklist_flow(self, datapath): """ Install flows to drop any packets with ip address blocks matching the blacklist. """ for entry in self._ip_blacklist: 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 blacklist: %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_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_flow(datapath, self.tbl_num, match, [], priority=flows.DEFAULT_PRIORITY)
def _install_default_flows(self, datapath): """ For every UE IP block, this adds a pair of 0-priority flow-miss rules for incoming and outgoing traffic which trigger PACKET IN. """ parser, ofproto = datapath.ofproto_parser, datapath.ofproto imsi_match = (0x1, 0x1) # match on the last bit set inbound_match = MagmaMatch(eth_type=ether_types.ETH_TYPE_IP, direction=Direction.IN, imsi=imsi_match) outbound_match = MagmaMatch(eth_type=ether_types.ETH_TYPE_IP, direction=Direction.OUT, imsi=imsi_match) actions = [ parser.OFPActionOutput(ofproto.OFPP_CONTROLLER, ofproto.OFPCML_NO_BUFFER) ] flows.add_flow(datapath, self.tbl_num, inbound_match, actions, priority=flows.MINIMUM_PRIORITY, cookie=self.DEFAULT_FLOW_COOKIE) flows.add_flow(datapath, self.tbl_num, outbound_match, actions, priority=flows.MINIMUM_PRIORITY, cookie=self.DEFAULT_FLOW_COOKIE)
def _install_not_processed_flows(self, datapath, imsi, rule, rule_num, priority): """ Redirect all traffic to the scratch table to only allow redirected http traffic to go through, the rest will be dropped. reg0 is used as a boolean to know whether the drop rule was processed. """ parser = datapath.ofproto_parser of_note = parser.NXActionNote(list(rule.id.encode())) match = MagmaMatch(imsi=encode_imsi(imsi), direction=Direction.OUT, reg0=self.REDIRECT_NOT_PROCESSED, eth_type=ether_types.ETH_TYPE_IP) action = [of_note] flows.add_flow(datapath, self.tbl_num, match, action, priority=priority, cookie=rule_num, hard_timeout=rule.hard_timeout, resubmit_table=self.REDIRECT_SCRATCH_TABLE) match = MagmaMatch(imsi=encode_imsi(imsi), direction=Direction.OUT, reg0=self.REDIRECT_PROCESSED) action = [of_note] flows.add_flow(datapath, self.tbl_num, match, action, priority=priority, cookie=rule_num, hard_timeout=rule.hard_timeout, resubmit_table=self.next_table)
def _install_default_flows(self, datapath): """ For each direction set the default flows to just forward to next table. The policies for each subscriber would be added when the IP session is created, by reaching out to the controller/PCRF. Args: datapath: ryu datapath struct """ parser = datapath.ofproto_parser inbound_match = MagmaMatch(eth_type=ether_types.ETH_TYPE_IP, direction=Direction.IN) outbound_match = MagmaMatch(eth_type=ether_types.ETH_TYPE_IP, direction=Direction.OUT) if self._dpi_enabled: actions = [parser.OFPActionOutput(self._mon_port_number)] else: actions = [] flows.add_flow(datapath, self.tbl_num, inbound_match, actions, priority=flows.MINIMUM_PRIORITY, resubmit_table=self.next_table) flows.add_flow(datapath, self.tbl_num, outbound_match, actions, priority=flows.MINIMUM_PRIORITY, resubmit_table=self.next_table)
def _install_default_flows(self, datapath): """ For each direction set the default flows to just forward to next table. The policies for each subscriber would be added when the IP session is created, by reaching out to the controller/PCRF. Args: datapath: ryu datapath struct """ parser = self._datapath.ofproto_parser # Setup flows to classify & mirror to sampling port inbound_match = MagmaMatch(eth_type=ether_types.ETH_TYPE_IP, direction=Direction.IN) outbound_match = MagmaMatch(eth_type=ether_types.ETH_TYPE_IP, direction=Direction.OUT) actions = [ parser.NXActionResubmitTable(table_id=self._classify_app_tbl_num) ] if self._dpi_enabled: actions.append(parser.OFPActionOutput(self._mon_port_number)) flows.add_resubmit_next_service_flow(datapath, self.tbl_num, inbound_match, actions, priority=flows.MINIMUM_PRIORITY, resubmit_table=self.next_table) flows.add_resubmit_next_service_flow(datapath, self.tbl_num, outbound_match, actions, priority=flows.MINIMUM_PRIORITY, resubmit_table=self.next_table) # Setup flows for internal IPFIX sampling actions = [ parser.NXActionResubmitTable(table_id=self._classify_app_tbl_num) ] if self._service_manager.is_app_enabled(IPFIXController.APP_NAME): flows.add_resubmit_next_service_flow( self._datapath, self._app_set_tbl_num, MagmaMatch(), actions, priority=flows.MINIMUM_PRIORITY, resubmit_table=self._imsi_set_tbl_num) # Setup flows for the application reg classifier tbl actions = [ parser.NXActionRegLoad2(dst=DPI_REG, value=UNCLASSIFIED_PROTO_ID) ] flows.add_flow(datapath, self._classify_app_tbl_num, MagmaMatch(), actions, priority=flows.MINIMUM_PRIORITY)
def _install_default_tunnel_flows(self): match = MagmaMatch() flows.add_flow(self._datapath, self.tbl_num, match, priority=flows.MINIMUM_PRIORITY, goto_table=self.next_table)
def add_classify_flow(self, flow_match, flow_state, app: str, service_type: str): """ Parse DPI output and set the register for future packets matching this flow. APP is split into tokens as the top level app is not supported, but the parent protocol might be. Example we care about google traffic, but don't neccessarily want to classify every specific google service. """ # TODO add error return if self._datapath is None: return parser = self._datapath.ofproto_parser app_id = get_app_id(app, service_type) try: ul_match = flow_match_to_magma_match(flow_match) ul_match.direction = None dl_match = flow_match_to_magma_match(flip_flow_match(flow_match)) dl_match.direction = None except FlowMatchError as e: self.logger.error(e) return actions = [parser.NXActionRegLoad2(dst=DPI_REG, value=app_id)] # No reason to create a flow here if flow_state != FlowRequest.FLOW_CREATED: flows.add_flow(self._datapath, self._classify_app_tbl_num, ul_match, actions, priority=flows.DEFAULT_PRIORITY, idle_timeout=self._idle_timeout) flows.add_flow(self._datapath, self._classify_app_tbl_num, dl_match, actions, priority=flows.DEFAULT_PRIORITY, idle_timeout=self._idle_timeout)
def _install_ipv4_bypass_flows(self, datapath, imsi, rule, rule_num, priority, ips): """ Installs flows for traffic that is allowed to pass through for subscriber who has redirection enabled. Allow access to all passed ips. Allow UDP traffic(for DNS queries), traffic to/from redirection address """ parser = datapath.ofproto_parser of_note = parser.NXActionNote(list(rule.id.encode())) actions = [parser.NXActionRegLoad2(dst='reg2', value=rule_num), of_note] matches = [] for ip in ips: matches.append(MagmaMatch( eth_type=ether_types.ETH_TYPE_IP, direction=Direction.OUT, ipv4_dst=ip, imsi=encode_imsi(imsi) )) matches.append(MagmaMatch( eth_type=ether_types.ETH_TYPE_IP, direction=Direction.IN, ipv4_src=ip, imsi=encode_imsi(imsi) )) for match in matches: flows.add_flow(datapath, self.tbl_num, match, actions, priority=priority + 1, cookie=rule_num, hard_timeout=rule.hard_timeout, resubmit_table=self.next_table)
def _install_internal_pkt_fwd_flow(self): match = MagmaMatch(in_port=self.config.internal_sampling_port) flows.add_flow(self._datapath, self.tbl_num, match, priority=flows.MINIMUM_PRIORITY, goto_table=self.config.internal_sampling_fwd_tbl)
def _install_default_flows(self, datapath): """ Default flow is to forward to next table. """ flows.add_flow(datapath, self.tbl_num, MagmaMatch(), [], priority=flows.MINIMUM_PRIORITY, resubmit_table=self.next_table)
def insert_flow(self, ryu_req): """ Parse the ryu request and add flow to the ovs table """ actions = to_instructions(self._datapath, ryu_req["instructions"]) flows.add_flow( self._datapath, ryu_req["table_id"], ryu_req["match"], instructions=actions, priority=ryu_req["priority"] )
def _install_forward_flow(self, datapath): """ Set a simple forward flow for when metering is disabled """ match = MagmaMatch() flows.add_flow(datapath, self.tbl_num, match, [], priority=flows.MINIMUM_PRIORITY, resubmit_table=self.next_table)
def _set_default_forward_flow(self, datapath): """ Set a default 0-priority flow to forward to the next table. """ match = MagmaMatch() flows.add_flow(datapath, self.table_num, match, [], priority=flows.MINIMUM_PRIORITY, resubmit_table=self.next_table)
def _set_incoming_arp_flows(self, datapath): """ Install a flow rule to respond in incoming ARP requests for UE IPs. Drop all other incoming ARPs. """ parser = datapath.ofproto_parser ofproto = datapath.ofproto # Set up ARP responder using flow rules. Add a rule with the following # actions for each UE IP block: # 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 for ip_block in self.config.ue_ip_blocks: match = MagmaMatch(eth_type=ether_types.ETH_TYPE_ARP, direction=Direction.IN, arp_tpa=ip_block) actions = [ parser.NXActionRegMove(src_field='eth_src', dst_field='eth_dst', n_bits=48), parser.OFPActionSetField(eth_src=self.config.virtual_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=self.config.virtual_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), parser.OFPActionOutput(ofproto.OFPP_IN_PORT), ] flows.add_flow(datapath, self.table_num, match, actions, priority=flows.DEFAULT_PRIORITY) # Drop all other ARPs match = MagmaMatch(eth_type=ether_types.ETH_TYPE_ARP, direction=Direction.IN) flows.add_flow(datapath, self.table_num, match, [], priority=flows.MINIMUM_PRIORITY)
def _add_tunnel_flows(self, precedence:int, i_teid:int, o_teid:int, ue_ip_adr:str, enodeb_ip_addr:str, sid:int = None): parser = self._datapath.ofproto_parser priority = Utils.get_of_priority(precedence) # Add flow for gtp port match = MagmaMatch(tunnel_id=i_teid, in_port=self.config.gtp_port) 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_flow(self._datapath, self.tbl_num, match, actions=actions, priority=priority, goto_table=self.next_table) # Add flow for LOCAL port match = MagmaMatch(eth_type=ether_types.ETH_TYPE_IP,in_port=self._uplink_port, ipv4_dst=ue_ip_adr) actions = [parser.OFPActionSetField(tunnel_id=o_teid), parser.OFPActionSetField(tun_ipv4_dst=enodeb_ip_addr), parser.NXActionRegLoad2(dst=TUN_PORT_REG, value=self.config.gtp_port)] if sid: actions.append(parser.OFPActionSetField(metadata=sid)) flows.add_flow(self._datapath, self.tbl_num, match, actions=actions, priority=priority, goto_table=self.next_table) # Add flow for mtr port match = MagmaMatch(eth_type=ether_types.ETH_TYPE_IP, in_port=self.config.mtr_port, ipv4_dst=ue_ip_adr) flows.add_flow(self._datapath, self.tbl_num, match, actions=actions, priority=priority, goto_table=self.next_table) # Add ARP flow for LOCAL port match = MagmaMatch(eth_type=ether_types.ETH_TYPE_ARP, in_port=self._uplink_port, arp_tpa=ue_ip_adr) actions = [] if sid: actions = [parser.OFPActionSetField(metadata=sid)] flows.add_flow(self._datapath, self.tbl_num, match, actions=actions, priority=priority, goto_table=self.next_table) # Add ARP flow for mtr port match = MagmaMatch(eth_type=ether_types.ETH_TYPE_ARP, in_port=self.config.mtr_port, arp_tpa=ue_ip_adr) flows.add_flow(self._datapath, self.tbl_num, match, actions=actions, priority=priority, goto_table=self.next_table)
def _install_drop_flow(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_flow(self._datapath, self.tbl_num, match, actions, priority=self.ENFORCE_DROP_PRIORITY)
def _install_new_ingress_egress_flows(self, ev): """ For every packet not already matched by a flow rule, install a pair of flows to track all packets to/from the corresponding IMSI. """ msg = ev.msg datapath = msg.datapath parser = datapath.ofproto_parser if not self._matches_table(msg): # Intended for other application return try: # no need to decode the IMSI. The OFPMatch will # give the already-encoded IMSI value, and we can match on that imsi = _get_encoded_imsi_from_packetin(msg) except MagmaOFError as e: # No packet direction, but intended for this table self.logging.error("Error obtaining IMSI from pkt-in: %s", e) return # Set inbound/outbound tracking flows flow_id_note = list(bytes(str(uuid.uuid4()), 'utf-8')) outbound_match = MagmaMatch(eth_type=ether_types.ETH_TYPE_IP, direction=Direction.IN, imsi=imsi) outbound_actions = [parser.NXActionNote(note=flow_id_note)] inbound_match = MagmaMatch(eth_type=ether_types.ETH_TYPE_IP, direction=Direction.OUT, imsi=imsi) inbound_actions = [parser.NXActionNote(note=flow_id_note)] flows.add_flow(datapath, self.tbl_num, inbound_match, inbound_actions, priority=flows.DEFAULT_PRIORITY, idle_timeout=self.config.idle_timeout, resubmit_table=self.next_table) flows.add_flow(datapath, self.tbl_num, outbound_match, outbound_actions, priority=flows.DEFAULT_PRIORITY, idle_timeout=self.config.idle_timeout, resubmit_table=self.next_table)
def _install_default_egress_flows(self, dp): """ Egress table is the last table that a packet touches in the pipeline. Output downlink traffic to gtp port, uplink trafic to LOCAL Raises: MagmaOFError if any of the default flows fail to install. """ parser = dp.ofproto_parser downlink_match = MagmaMatch(direction=Direction.IN) downlink_actions = [parser.OFPActionOutput(self.config.gtp_port)] flows.add_flow(dp, self._service_manager.get_table_num(EGRESS), downlink_match, downlink_actions) uplink_match = MagmaMatch(direction=Direction.OUT) uplink_actions = [parser.OFPActionOutput(dp.ofproto.OFPP_LOCAL)] flows.add_flow(dp, self._service_manager.get_table_num(EGRESS), uplink_match, uplink_actions)
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.IN)] flows.add_flow(dp, tbl_num, match, actions=actions, priority=flows.DEFAULT_PRIORITY, resubmit_table=next_table) # set a direction bit for incoming (inet -> pn) traffic. match = MagmaMatch(in_port=dp.ofproto.OFPP_LOCAL) actions = [load_direction(parser, Direction.IN)] flows.add_flow(dp, tbl_num, match, actions=actions, priority=flows.DEFAULT_PRIORITY, resubmit_table=next_table)
def _set_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_flow(datapath, self.table_num, match, actions, priority=flows.MINIMUM_PRIORITY, resubmit_table=self.next_table)
def _discard_tunnel_flows(self, precedence: int, i_teid: int, ue_ip_adr: str): priority = Utils.get_of_priority(precedence) # discard uplink Tunnel match = MagmaMatch(tunnel_id=i_teid, in_port=self.config.gtp_port) flows.add_flow(self._datapath, self.tbl_num, match, priority=priority + 1) # discard downlink Tunnel for LOCAL port match = MagmaMatch(eth_type=ether_types.ETH_TYPE_IP, in_port=self._uplink_port, ipv4_dst=ue_ip_adr) flows.add_flow(self._datapath, self.tbl_num, match, priority=priority + 1) # discard downlink Tunnel for mtr port match = MagmaMatch(eth_type=ether_types.ETH_TYPE_IP, in_port=self.config.mtr_port, ipv4_dst=ue_ip_adr) flows.add_flow(self._datapath, self.tbl_num, match, priority=priority + 1)
def _install_dns_flows(self, datapath, imsi, rule, rule_num, priority): """ Installs flows that allow DNS queries to path thorugh. """ parser = datapath.ofproto_parser of_note = parser.NXActionNote(list(rule.id.encode())) actions = [ parser.NXActionRegLoad2(dst='reg2', value=rule_num), of_note, ] matches = [] # Install UDP flows for DNS matches.append(MagmaMatch(eth_type=ether_types.ETH_TYPE_IP, ip_proto=IPPROTO_UDP, udp_src=53, direction=Direction.IN, imsi=encode_imsi(imsi))) matches.append(MagmaMatch(eth_type=ether_types.ETH_TYPE_IP, ip_proto=IPPROTO_UDP, udp_dst=53, direction=Direction.OUT, imsi=encode_imsi(imsi))) # Install TCP flows for DNS matches.append(MagmaMatch(eth_type=ether_types.ETH_TYPE_IP, ip_proto=IPPROTO_TCP, tcp_src=53, direction=Direction.IN, imsi=encode_imsi(imsi))) matches.append(MagmaMatch(eth_type=ether_types.ETH_TYPE_IP, ip_proto=IPPROTO_TCP, tcp_dst=53, direction=Direction.OUT, imsi=encode_imsi(imsi))) for match in matches: flows.add_flow(datapath, self.tbl_num, match, actions, priority=priority, cookie=rule_num, hard_timeout=rule.hard_timeout, resubmit_table=self.next_table)
def _install_default_flows(self, datapath): """ For each direction set the default flows to just forward to next table. The enforcement flows for each subscriber would be added when the IP session is created, by reaching out to the controller/PCRF. Args: datapath: ryu datapath struct """ inbound_match = MagmaMatch(eth_type=ether_types.ETH_TYPE_IP, direction=Direction.IN) outbound_match = MagmaMatch(eth_type=ether_types.ETH_TYPE_IP, direction=Direction.OUT) flows.add_flow(datapath, self.tbl_num, inbound_match, [], priority=flows.MINIMUM_PRIORITY, resubmit_table=self.next_table) flows.add_flow(datapath, self.tbl_num, outbound_match, [], priority=flows.MINIMUM_PRIORITY, resubmit_table=self.next_table)
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_flow(self._datapath, self.tbl_num, MagmaMatch(**ryu_match), actions, priority=flows.DEFAULT_PRIORITY, resubmit_table=self.next_table) return True
def add_tunnel_flows(self, precedence: int, i_teid: int, o_teid: int, ue_ip_adr: str, 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_flow(self._datapath, self.tbl_num, match, actions=actions, priority=priority, goto_table=self.next_table) # Install Downlink Tunnel actions = [] if ue_ip_adr: if o_teid and enodeb_ip_addr: # Add flow for LOCAL port match = MagmaMatch(eth_type=ether_types.ETH_TYPE_IP, in_port=self._uplink_port, ipv4_dst=ue_ip_adr) 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_flow(self._datapath, self.tbl_num, match, actions=actions, priority=priority, goto_table=self.next_table) # Add flow for mtr port match = MagmaMatch(eth_type=ether_types.ETH_TYPE_IP, in_port=self.config.mtr_port, ipv4_dst=ue_ip_adr) flows.add_flow(self._datapath, self.tbl_num, match, actions=actions, priority=priority, goto_table=self.next_table) # Add ARP flow for LOCAL port match = MagmaMatch(eth_type=ether_types.ETH_TYPE_ARP, in_port=self._uplink_port, arp_tpa=ue_ip_adr) actions = [] if sid: actions = [parser.OFPActionSetField(metadata=sid)] flows.add_flow(self._datapath, self.tbl_num, match, actions=actions, priority=priority, goto_table=self.next_table) # Add ARP flow for mtr port match = MagmaMatch(eth_type=ether_types.ETH_TYPE_ARP, in_port=self.config.mtr_port, arp_tpa=ue_ip_adr) flows.add_flow(self._datapath, self.tbl_num, match, actions=actions, priority=priority, goto_table=self.next_table) return True
def _install_server_flows(self, datapath, imsi, rule, rule_num, priority): """ The flow action for subcribers 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.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.value, 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='reg2', value=rule_num), parser.OFPActionSetField(ipv4_dst=self._bridge_ip), parser.OFPActionSetField(tcp_dst=self._redirect_port), of_note ] flows.add_flow(datapath, self.tbl_num, match_http, actions, priority=priority, cookie=rule_num, hard_timeout=rule.hard_timeout, resubmit_table=self.next_table)