def natv6_flows(self, nfvip): nat_base = nfvip.network.network_address assert nfvip.network.prefixlen == 64, 'NFVIPS IPv4 all must be /64' # pylint: disable=no-member return self.apply_actions([ # ipv6_src fc01::5 -> fc04::5:0:1, ipv6_dst fc01::1 -> fc04::1 parser.NXActionRegLoad(value=(int(nat_base) & ((2**64) - 1)), dst=self.AREG, ofs_nbits=nicira_ext.ofs_nbits(0, 63)), parser.NXActionRegLoad(value=(int(nat_base) >> 64), dst=self.AREG, ofs_nbits=nicira_ext.ofs_nbits(64, 127)), ] + self.nat_actions(ether.ETH_TYPE_IPV6, nfvip, 32))
def arp_reply_actions(self): # pylint: disable=no-member common_reply = self.common_reply_actions() return self.apply_actions([ parser.NXActionRegLoad(value=arp.ARP_REPLY, dst='arp_op', ofs_nbits=nicira_ext.ofs_nbits(0, 2)), parser.NXActionRegMove(src_field='arp_sha', dst_field='arp_tha', n_bits=48, src_ofs=0, dst_ofs=0), parser.NXActionRegMove(src_field='arp_tpa', dst_field=self.AREG, n_bits=32, src_ofs=0, dst_ofs=0), parser.NXActionRegMove(src_field='arp_spa', dst_field='arp_tpa', n_bits=32, src_ofs=0, dst_ofs=0), parser.NXActionRegMove(src_field=self.AREG, dst_field='arp_spa', n_bits=32, src_ofs=0, dst_ofs=0), parser.OFPActionSetField(arp_sha=FAKECLIENTMAC), ] + common_reply)
def _make_ingress_classification_flow(self, lport, port_num): match = self.parser.OFPMatch(in_port=port_num) network_id = lport.lswitch.unique_key LOG.debug( "match in_port=%(in_port)s for ingress classification " "of %(lport)s in network %(network)s", { 'in_port': port_num, 'lport': lport, 'network': network_id }) # Reset in_port to 0 to avoid drop by output command. actions = [ self.parser.OFPActionSetField(reg6=lport.unique_key), self.parser.OFPActionSetField(metadata=network_id), self.parser.NXActionRegLoad( dst='in_port', value=0, ofs_nbits=nicira_ext.ofs_nbits(0, 31), ), self.parser.NXActionResubmit(), ] self.mod_flow( table_id=const.INGRESS_CLASSIFICATION_DISPATCH_TABLE, priority=const.PRIORITY_MEDIUM, match=match, actions=actions, )
def _get_rewrite_ip_and_output_actions(self, ofproto, parser): """ Retrieve the actions that rewrite the dst IP field with the reg6 (the tunnel key), set the first bit of that field, and output to the metadata service OVS port. The IP is set to <reg6> | 0x8000000, so that the transparent proxy can extract the <reg6> from the source IP address, and be able to identify the source VM. reg6 holds the local DF id identifying the VM. """ return [ parser.NXActionRegMove( src_field='reg6', dst_field='ipv4_src', n_bits=32, ), parser.NXActionRegLoad( ofs_nbits=nicira_ext.ofs_nbits(31, 31), dst="ipv4_src", value=1, ), parser.OFPActionOutput( self._port_num, ofproto.OFPCML_NO_BUFFER, ) ]
def _install_snat_egress_conntrack(self, match, ext_host_ip): """implements single sNAT pass for multiple tenant deployment :param match: - OVS match expression passed as a parameter :param ext_host_ip: - unique ip to translate tenant IPs to it :returns: None ----Translation logic follows next rules:---- ipv4_src -> reg5 (temporary save internal tenant local IP) reg6 -> ipv4_src (replace content of ipv4_src with host unique value) last_bit(1) -> ipv4_src (turn unique value into legal IP address) reg6-> ct_mark (save unique value associated with port into OS conn. track table) reg5 -> ct_label (save original tenant local IP for return flow) """ parser = self.parser ofproto = self.ofproto actions = [ parser.NXActionRegMove(src_field='ipv4_src', dst_field='reg5', n_bits=32), parser.NXActionRegMove(src_field='reg6', dst_field='ipv4_src', n_bits=32), parser.NXActionRegLoad( ofs_nbits=nicira_ext.ofs_nbits(31, 31), dst="ipv4_src", value=1, ), parser.NXActionCT(alg=0, flags=const.CT_FLAG_COMMIT, recirc_table=const.EGRESS_SNAT_TABLE, zone_ofs_nbits=const.NAT_TRACKING_ZONE, zone_src='', actions=[ parser.NXActionNAT( flags=const.CT_FLAG_COMMIT, range_ipv4_min=ext_host_ip, range_ipv4_max=ext_host_ip, ), parser.NXActionRegMove(dst_field='ct_mark', src_field='reg6', n_bits=32), parser.NXActionRegMove(dst_field='ct_label', src_field='reg5', n_bits=32), ]) ] action_inst = parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS, actions) inst = [action_inst] self.mod_flow(inst=inst, table_id=const.EGRESS_NAT_TABLE, priority=const.PRIORITY_LOW, match=match)
def natv4_flows(self, nfvip): nat_base = nfvip.network.network_address assert nfvip.network.prefixlen == 16, 'NFVIPS IPv4 all must be /16' # pylint: disable=no-member return self.apply_actions([ # ipv4_src 192.168.2.5->10.10.5.1, ipv4_dst 192.168.2.1->10.10.0.1 parser.NXActionRegLoad(value=int(nat_base), dst=self.AREG, ofs_nbits=nicira_ext.ofs_nbits(0, 31)), ] + self.nat_actions(ether.ETH_TYPE_IP, nfvip, 8))
def ct(cls, ofproto, action_str): str_to_port = {'ftp': 21, 'tftp': 69} flags = 0 zone_src = "" zone_ofs_nbits = 0 recirc_table = nicira_ext.NX_CT_RECIRC_NONE alg = 0 ct_actions = [] if len(action_str) > 2: if (not action_str.startswith('ct(') or action_str[-1] != ')'): raise os_ken.exception.OFPInvalidActionString( action_str=action_str) rest = tokenize_ofp_instruction_arg(action_str[len('ct('):-1]) else: rest = [] for arg in rest: if arg == 'commit': flags |= nicira_ext.NX_CT_F_COMMIT rest = rest[len('commit'):] elif arg == 'force': flags |= nicira_ext.NX_CT_F_FORCE elif arg.startswith('exec('): ct_actions = ofp_instruction_from_str(ofproto, arg[len('exec('):-1]) else: try: k, v = arg.split('=', 1) if k == 'table': recirc_table = str_to_int(v) elif k == 'zone': m = re.search(r'\[(\d*)\.\.(\d*)\]', v) if m: zone_ofs_nbits = nicira_ext.ofs_nbits( int(m.group(1)), int(m.group(2))) zone_src = nxm_field_name_to_os_ken(v[:m.start(0)]) else: zone_ofs_nbits = str_to_int(v) elif k == 'alg': alg = str_to_port[arg[len('alg='):]] except Exception: raise os_ken.exception.OFPInvalidActionString( action_str=action_str) return dict( NXActionCT={ 'flags': flags, 'zone_src': zone_src, 'zone_ofs_nbits': zone_ofs_nbits, 'recirc_table': recirc_table, 'alg': alg, 'actions': ct_actions })
def _install_snat_ingress_after_conntrack(self, unique_key, vm_mac, network_id, external_host_mac): """complements reverse sNAT translation from unique IP to tenant IP :param unique_key: - key to match with :param vm_mac: - original VM mac address to restore :returns: None ---Translation complement follows next rules:--- unique_key -> reg7 ( load unique port key into dedicated register) ct_label -> ipv4_src (restore original local tenant IP) change src/dst mac addresses to push packet further to destination """ parser = self.parser ofproto = self.ofproto match = parser.OFPMatch(eth_type=ether.ETH_TYPE_IP, ct_mark=int(unique_key)) actions = [ parser.OFPActionSetField(eth_src=external_host_mac), parser.OFPActionSetField(eth_dst=vm_mac), parser.NXActionRegLoad(ofs_nbits=nicira_ext.ofs_nbits(0, 31), dst='reg7', value=unique_key), parser.NXActionRegMove(src_field='ct_label', dst_field='ipv4_dst', n_bits=32), parser.OFPActionSetField(metadata=network_id), ] action_inst = parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS, actions) goto_inst = parser.OFPInstructionGotoTable( const.INGRESS_DESTINATION_PORT_LOOKUP_TABLE) inst = [action_inst, goto_inst] self.mod_flow(inst=inst, table_id=const.INGRESS_SNAT_TABLE, priority=const.PRIORITY_LOW, match=match) actions = [ self.parser.OFPActionOutput(self.external_ofport, self.ofproto.OFPCML_NO_BUFFER) ] self.mod_flow(actions=actions, table_id=const.INGRESS_DISPATCH_TABLE, priority=const.PRIORITY_DEFAULT)
def _install_ingress_goto_rules(self): parser = self.parser #匹配external_ofport (br-int桥上连接br-ex的port) match = parser.OFPMatch(in_port=self.external_ofport) actions = [ parser.NXActionRegLoad(dst='in_port', value=0, ofs_nbits=nicira_ext.ofs_nbits(0, 31)) ] inst = [ parser.OFPInstructionActions( self.datapath.ofproto.OFPIT_APPLY_ACTIONS, actions), parser.OFPInstructionGotoTable(const.INGRESS_NAT_TABLE) ] self.mod_flow(inst=inst, table_id=const.INGRESS_CLASSIFICATION_DISPATCH_TABLE, priority=const.PRIORITY_DEFAULT, match=match)
def _install_dispatch_flows(self, flow_classifier): lport = self._get_flow_classifier_lport(flow_classifier) # End-of-chain # 1) Restore network ID in metadata and zero reg6 + reg2 # 2) Restore port ID in reg7 in dest port # 3) Resubmit to the next table lswitch = lport.lswitch actions = [ self.parser.OFPActionSetField(metadata=lswitch.unique_key), self.parser.OFPActionSetField(reg6=0), self.parser.OFPActionSetField(reg2=0), ] if flow_classifier.source_port == lport: done_bit = _SRC_BIT elif flow_classifier.dest_port == lport: done_bit = _DST_BIT # FIXME (dimak) maybe get it from L2 table actions.append( self.parser.OFPActionSetField(reg7=lport.unique_key)) actions += [ self.parser.NXActionRegLoad( dst='reg3', value=1, ofs_nbits=nicira_ext.ofs_nbits(done_bit, done_bit), ), self.parser.NXActionResubmitTable( table_id=self._get_flow_classifier_table(flow_classifier)) ] self.mod_flow( table_id=constants.SFC_END_OF_CHAIN_TABLE, priority=constants.PRIORITY_MEDIUM, match=self.parser.OFPMatch(reg2=flow_classifier.unique_key), actions=actions, )
def _match_actions_by_network_type(self, lport, network_id, network_type): actions = [ self.parser.NXActionRegLoad( dst='in_port', value=0, ofs_nbits=nicira_ext.ofs_nbits(0, 31), ), self.parser.OFPActionSetField(metadata=network_id), ] if network_type == NET_VLAN: vlan_vid = self.ofproto.OFPVID_PRESENT vlan_vid |= lport.lswitch.segmentation_id actions.append(self.parser.OFPActionPopVlan()) elif network_type == NET_FLAT: vlan_vid = 0 match = self.parser.OFPMatch( in_port=self.int_ofports[lport.lswitch.physical_network], vlan_vid=vlan_vid, ) return match, actions
def nat_actions(self, eth_type, nfvip, nat_offset): ip_ver = nfvip.ip.version ip_src_nxm = 'ipv%u_src_nxm' % ip_ver ip_dst_nxm = 'ipv%u_dst_nxm' % ip_ver ipbits = nfvip.ip.max_prefixlen # pylint: disable=no-member return [ parser.NXActionRegMove(src_field='ipv%u_src' % ip_ver, dst_field=self.AREG, n_bits=nat_offset, src_ofs=0, dst_ofs=nat_offset), parser.NXActionRegMove(src_field='ipv%u_dst' % ip_ver, dst_field=self.AREG, n_bits=nat_offset, src_ofs=0, dst_ofs=0), # we have to load output port numbers into reg1 and reg2 because NXFlowSpecOutput() won't take a literal. parser.NXActionRegLoad(value=FAKEPORT, dst=self.FAKEPORTREG, ofs_nbits=nicira_ext.ofs_nbits(0, 15)), parser.NXActionRegLoad(value=COPROPORT, dst=self.COPROPORTREG, ofs_nbits=nicira_ext.ofs_nbits(0, 15)), # now program an inbound flow to perform NAT. parser.NXActionLearn( table_id=self.FROM_COPRO_TABLE, priority=2, hard_timeout=self.IDLE, specs=[ parser.NXFlowSpecMatch( src=eth_type, dst=('eth_type_nxm', 0), n_bits=16), parser.NXFlowSpecMatch(src=(ip_src_nxm, 0), dst=(ip_src_nxm, 0), n_bits=ipbits), parser.NXFlowSpecMatch(src=(ip_dst_nxm, 0), dst=(ip_dst_nxm, 0), n_bits=ipbits), parser.NXFlowSpecLoad(src=int(FAKECLIENTMAC), dst=('eth_src_nxm', 0), n_bits=48), parser.NXFlowSpecLoad(src=int(FAKESERVERMAC), dst=('eth_dst_nxm', 0), n_bits=48), ] + self.reg_copy(self.AREG, ip_src_nxm, ipbits) + [ parser.NXFlowSpecLoad( src=int(nfvip.ip), dst=(ip_dst_nxm, 0), n_bits=ipbits), parser.NXFlowSpecOutput( src=(self.FAKEPORTREG, 0), dst='', n_bits=16), ]), # now program outbound an outbound flow. parser.NXActionLearn( table_id=self.TO_COPRO_TABLE, priority=2, idle_timeout=self.IDLE, specs=[ parser.NXFlowSpecMatch( src=eth_type, dst=('eth_type_nxm', 0), n_bits=16), parser.NXFlowSpecMatch(src=int(nfvip.ip), dst=(ip_src_nxm, 0), n_bits=ipbits), ] + self.reg_copy(self.AREG, ip_dst_nxm, ipbits) + [ parser.NXFlowSpecLoad(src=('eth_dst_nxm', 0), dst=('eth_src_nxm', 0), n_bits=48), parser.NXFlowSpecLoad(src=('eth_src_nxm', 0), dst=('eth_dst_nxm', 0), n_bits=48), parser.NXFlowSpecLoad(src=(ip_dst_nxm, 0), dst=(ip_src_nxm, 0), n_bits=ipbits), parser.NXFlowSpecLoad(src=(ip_src_nxm, 0), dst=(ip_dst_nxm, 0), n_bits=ipbits), parser.NXFlowSpecOutput( src=(self.COPROPORTREG, 0), dst='', n_bits=16), ]), # now that future flows are programmed, handle the packet we have. parser.OFPActionSetField(eth_src=FAKECLIENTMAC), parser.OFPActionSetField(eth_dst=FAKESERVERMAC), parser.NXActionRegMove(src_field=self.AREG, dst_field=('ipv%u_src' % ip_ver), n_bits=ipbits, src_ofs=0, dst_ofs=0), parser.OFPActionSetField(**{'ipv%u_dst' % ip_ver: str(nfvip.ip)}), parser.OFPActionOutput(FAKEPORT) ]