def packet_to_flow_match(packet): """ Create a flow match that matches packet with the given wildcards @param packet The packet to use as a flow template @param pkt_format Currently only L2 is supported. Will indicate the overall packet type for parsing @return An ofp_match object if successful. None if format is not recognized. The wildcards of the match will be cleared for the values extracted from the packet. @todo check min length of packet @todo Check if packet is other than L2 format @todo implement other fields covered by OpenFlow 1.2 """ match_ls = match_list() if Ether in packet: ether = packet[Ether] eth_type = match.eth_type(ether.type) eth_dst = match.eth_dst(parse_mac(ether.dst)) eth_src = match.eth_src(parse_mac(ether.src)) match_ls.add(eth_type) match_ls.add(eth_dst) match_ls.add(eth_src) else: return match_ls if Dot1Q in packet: #TODO: nicer way to get last vlan tag? vlan = packet[Dot1Q:0] vlan_vid = match.vlan_vid(vlan.vlan) vlan_pcp = match.vlan_pcp(vlan.prio) match_ls.add(vlan_vid) match_ls.add(vlan_pcp) vlan_pl = vlan.payload while vlan_pl is not None and vlan_pl.name == Dot1Q.name: vlan = vlan_pl vlan_pl = vlan.payload #We need to overwrite the already # inserted eth_type eth_index = match.tlvs.index() eth_type = match.eth_type(vlan.type) match_ls.tlvs.insert(vlan.type,eth_index) #TODO ARP if MPLS in packet: mpls = packet[MPLS:0] mpls_label = match.mpls_label(mpls.label) mpls_tc = match.mpls_tc(mpls.cos) match_ls.add(mpls_label) match_ls.add(mpls_tc) return match_ls if IP in packet: ip = packet[IP] ipv4_src = match.ipv4_src(parse_ip(ip.src)) ipv4_dst = match.ipv4_dst(parse_ip(ip.dst)) ip_dscp = match.ip_dscp(ip.tos >> 2) ip_ecn = match.ip_ecn(ip.tos & 0x03) match_ls.add(ipv4_src) match_ls.add(ipv4_dst) match_ls.add(ip_dscp) match_ls.add(ip_ecn) else: return match_ls if TCP in packet: tcp = packet[TCP] ip_proto = match.ip_proto(6) tcp_src = match.tcp_src(tcp.sport) tcp_dst = match.tcp_dst(tcp.dport) match_ls.add(ip_proto) match_ls.add(tcp_src) match_ls.add(tcp_dst) return match_ls if UDP in packet: udp = packet[UDP] ip_proto = match.ip_proto(17) udp_src = match.tcp_src(udp.sport) udp_dst = match.tcp_dst(udp.dport) match_ls.add(ip_proto) match_ls.add(udp_src) match_ls.add(udp_dst) return match_ls if ICMP in packet: icmp = packet[ICMP] ip_proto = match.ip_proto(1) icmp_type = match.icmp_type(icmp.type) icmp_code = match.icmp_code(icmp.code) match_ls.add(icmp_type) match_ls.add(icmp_code) return match_ls return match_ls
def init_lrp_egress_clause(options): # figure out all linked lsp on a LS which has a connection with this LRP opposite_side_changed_lsp( LR, LRP, LSP, State) <= (lsp_link_lrp( LSP1, LS, UUID_LS, LRP, LR, UUID_LR, UUID_LR_CHASSIS, State1) & exchange_lsp_array( UUID_LSP, LSP, UUID_LS, UUID_CHASSIS, UUID_LRP1, State2) & (State == State1 + State2) & (State != 0)) # figure out all regular lsp opposite_side_changed_lsp(LR, LRP, LSP, State) <= ( lrp_array(UUID_LRP, LRP, UUID_LR, UUID_LSP1, State1) & exchange_lsp_array(UUID_LSP1, LSP1, UUID_LS, UUID_CHASSIS1, UUID_LRP, State2) & ls_array(LS, UUID_LS, State3) & lr_array(LR, UUID_LR, State4) & lsp_array(UUID_LSP, LSP, UUID_LS, UUID_CHASSIS2, UUID_LRP2, State5) & (UUID_CHASSIS2 != None) & (State == State1 + State2 + State3 + State4 + State5) & (State != 0)) opposite_side_has_patch_port(LR, LRP, State) <= ( local_patchport(LSP, LS, State1) & lsp_link_lrp( LSP1, LS, UUID_LS, LRP, LR, UUID_LR, UUID_LR_CHASSIS, State2) & # NOTE only consider local_patchport, it means a gateway's oppsite # LS has remote patchport cannot trigger this flow (State == State1 + State2)) # update eth_dst by searching active lsp lrp_update_eth_dst(LR, Priority, Match, Action, State) <= ( (Priority == 3) & opposite_side_changed_lsp(LR, LRP, LSP, State) & match.ip_proto(Match1) & # we have to match the lrp portID, because in ecmp, # two ports may have same dst IP but different dst mac match.reg_dst(LRP[LRP_PORTID], Match2) & match.reg_2(LSP[LSP_IP_INT], Match3) & (Match == Match1 + Match2 + Match3) & action.load(LSP[LSP_MAC_INT], NXM_Reg(ETH_DST_IDX), Action1) & action.resubmit_next(Action2) & (Action == Action1 + Action2)) # push packet to table TABLE_SEARCH_IP_MAC to search unknow mac,ip pair lrp_update_eth_dst(LR, Priority, Match, Action, State) <= ( (Priority == 2) & lr_array(LR, UUID_LR, State) & (State != 0) & match.match_none(Match) & action.mod_dl_dst("00:00:00:00:00:00", Action1) & action.resubmit_table(TABLE_SEARCH_IP_MAC, Action2) & action.resubmit_next(Action3) & (Action == Action1 + Action2 + Action3)) lrp_ip_undnat_stage1(LR, Priority, Match, Action, State) <= (nat.lundnat_xlate_stage1( LR, Priority, Match, Action, State)) lrp_ip_undnat_stage2(LR, Priority, Match, Action, State) <= (nat.lundnat_xlate_stage2( LR, Priority, Match, Action, State)) lrp_ip_snat_stage1(LR, Priority, Match, Action, State) <= (nat.lsnat_xlate_stage1( LR, Priority, Match, Action, State)) lrp_ip_snat_stage2(LR, Priority, Match, Action, State) <= (nat.lsnat_xlate_stage2( LR, Priority, Match, Action, State)) # ovs should drop it if the packet's dst_mac = 00:00:00:00:00:00 and # it is a redirect packet. This flow avoids infinite loop. lrp_handle_unknow_dst_pkt(LR, Priority, Match, Action, State) <= ( (Priority == 4) & lr_array(LR, UUID_LR, State) & (State != 0) & match.reg_flag(FLAG_REDIRECT, Match1) & match.eth_dst("00:00:00:00:00:00", Match2) & (Match == Match1 + Match2) & action.resubmit_table(TABLE_DROP_PACKET, Action)) # ask controller to generate arp, if we cannot found the ip,mac pair. # If opposite LS has patch-port will create this flow lrp_handle_unknow_dst_pkt(LR, Priority, Match, Action, State) <= ( (Priority == 3) & # oppsite LS must has patchport opposite_side_has_patch_port(LR, LRP, State) & (State != 0) & match.ip_proto(Match1) & match.eth_dst("00:00:00:00:00:00", Match2) & match.reg_dst(LRP[LRP_PORTID], Match3) & (Match == Match1 + Match2 + Match3) & # reg2 and reg3 were transfered to pkt_controller as well action.generate_arp(TABLE_LRP_EGRESS_FORWARD_PACKET, Action1) & action.resubmit_table(TABLE_DROP_PACKET, Action2) & (Action == Action1 + Action2)) # upload packet to controller, if this packet cannot trigger generating # arp and didn't know the destination's macaddress. controller will # ask tuplenet to generate it. if options.has_key('ONDEMAND'): if options.has_key('ENABLE_REDIRECT'): # A regular tuplenet node(with ondemand) may not know where dst lsp is, # so it uploads packet to controller and redirects pkt to an edge node. lrp_handle_unknow_dst_pkt(LR, Priority, Match, Action, State) <= ( (Priority == 2) & lr_array(LR, UUID_LR, State) & (State != 0) & match.ip_proto(Match1) & # set macaddress to 0, then other host know this packet # should be threw to LR pipline match.eth_dst("00:00:00:00:00:00", Match2) & (Match == Match1 + Match2) & action.load( 1, NXM_Reg(REG_FLAG_IDX, FLAG_REDIRECT_BIT_IDX, FLAG_REDIRECT_BIT_IDX), Action1) & action.upload_unknow_dst(Action2) & action.resubmit_table(TABLE_EMBED2_METADATA, Action3) & action.resubmit_table(TABLE_REDIRECT_CHASSIS, Action4) & (Action == Action1 + Action2 + Action3 + Action4)) else: lrp_handle_unknow_dst_pkt(LR, Priority, Match, Action, State) <= ( (Priority == 2) & lr_array(LR, UUID_LR, State) & (State != 0) & match.ip_proto(Match1) & match.eth_dst("00:00:00:00:00:00", Match2) & (Match == Match1 + Match2) & action.upload_unknow_dst(Action)) else: if options.has_key('ENABLE_REDIRECT'): # A edge node(with ondemand disable) should know where is dst, but # tuplenet instance may down so ovs-flow doesn't know the new dst( # a lsp may be create while tuplenet is down, ovs-flow not updated). # This ovs-flow should redirect this packet to other edge now as well, # BUT NOT upload to controller lrp_handle_unknow_dst_pkt(LR, Priority, Match, Action, State) <= ( (Priority == 2) & lr_array(LR, UUID_LR, State) & (State != 0) & match.ip_proto(Match1) & # set macaddress to 0, then other host know this packet # should be threw to LR pipline match.eth_dst("00:00:00:00:00:00", Match2) & (Match == Match1 + Match2) & action.load( 1, NXM_Reg(REG_FLAG_IDX, FLAG_REDIRECT_BIT_IDX, FLAG_REDIRECT_BIT_IDX), Action1) & action.resubmit_table(TABLE_EMBED2_METADATA, Action2) & action.resubmit_table(TABLE_REDIRECT_CHASSIS, Action3) & (Action == Action1 + Action2 + Action3)) lrp_handle_unknow_dst_pkt(LR, Priority, Match, Action, State) <= ( (Priority == 1) & lr_array(LR, UUID_LR, State) & (State != 0) & match.eth_dst("00:00:00:00:00:00", Match) & action.resubmit_table(TABLE_DROP_PACKET, Action)) lrp_handle_unknow_dst_pkt(LR, Priority, Match, Action, State) <= ( (Priority == 0) & lr_array(LR, UUID_LR, State) & (State != 0) & match.match_none(Match) & action.resubmit_next(Action)) lrp_forward_packet(LR, Priority, Match, Action, State) <= ( (Priority == 3) & lsp_link_lrp(LSP, LS, UUID_LS, LRP, LR, UUID_LR, UUID_LR_CHASSIS, State) & (State != 0) & match.reg_dst(LRP[LRP_PORTID], Match) & action.load(LS[LS_ID], NXM_Reg(REG_DP_IDX), Action1) & action.load(LSP[LSP_PORTID], NXM_Reg(REG_SRC_IDX), Action2) & action.resubmit_next(Action3) & (Action == Action1 + Action2 + Action3))
def init_lsp_ingress_clause(options): if options.has_key('GATEWAY'): # push RARP to controller, only Edge node should consider receiving rarp lsp_arp_controller(LS, Priority, Match, Action, State) <= ( (Priority == 2) & ls_array(LS, UUID_LS, State) & (State != 0) & match.arp_proto(Match1) & match.arp_op(2, Match2) & (Match == Match1 + Match2) & action.upload_arp(Action) ) if not options.has_key('ONDEMAND'): # maybe gratuitous ARP, push to controller. # maybe a unknow dst arp lsp_arp_controller(LS, Priority, Match, Action, State) <= ( (Priority == 1) & ls_array(LS, UUID_LS, State) & (State != 0) & match.arp_proto(Match1) & match.arp_op(1, Match2) & (Match == Match1 + Match2) & action.upload_arp(Action1) & action.resubmit_next(Action2) & (Action == Action1 + Action2) ) lsp_arp_controller(LS, Priority, Match, Action, State) <= ( (Priority == 0) & ls_array(LS, UUID_LS, State) & (State != 0) & (match.match_none(Match)) & action.resubmit_next(Action) ) lsp_arp_response(LS, Priority, Match, Action, State) <= ( (Priority == 2) & ls_array(LS, UUID_LS, State) & (State != 0) & match.arp_proto(Match1) & match.arp_op(1, Match2) & (Match == Match1 + Match2) & action.resubmit_table(TABLE_ARP_FEEDBACK_CONSTRUCT, Action1) & action.resubmit_next(Action2) & (Action == Action1 + Action2) ) lsp_arp_response(LS, Priority, Match, Action, State) <= ( (Priority == 0) & ls_array(LS, UUID_LS, State) & (State != 0) & (match.match_none(Match)) & action.resubmit_next(Action) ) if options.has_key('ENABLE_UNTUNNEL') and options.has_key('dsrport'): # NOTE: it helps reduce time-cost _lsp_lrp_ls_changed(LS, LRP, State) <= ( ls_array(LS, UUID_LS, State1) & lsp_link_lrp(LSP, LS1, UUID_LS1, LRP, LR, UUID_LR, UUID_LR_CHASSIS, State2) & (State == State1 + State2) & (State != 0) ) lsp_untunnel_deliver(LS, Priority, Match, Action, State) <= ( _lsp_lrp_ls_changed(LS, LRP, State) & (Priority == _cal_priority(LRP[LRP_PREFIX], 2, LRP[LRP_ILK_IDX])) & match.ip_proto(Match1) & match.ip_dst_prefix(LRP[LRP_IP], LRP[LRP_PREFIX], Match2) & (Match == Match1 + Match2) & action.resubmit_next(Action) ) lsp_untunnel_deliver(LS, Priority, Match, Action, State) <= ( (Priority == 1) & ls_array(LS, UUID_LS, State) & (State != 0) & match.ip_proto(Match) & # output packet to local port which is an internal port. # packet goes into tcpip stack action.mod_dl_dst(options['dsrport']['mac'], Action1) & action.output(options['dsrport']['ofport'], Action2) & (Action == Action1 + Action2) ) lsp_untunnel_deliver(LS, Priority, Match, Action, State) <= ( (Priority == 0) & ls_array(LS, UUID_LS, State) & (State != 0) & (match.match_none(Match)) & action.resubmit_next(Action) ) # deliver to LR which has snat/dnat lsp_lookup_dst_port(LS, Priority, Match, Action, State) <= ( (Priority == 5) & # TODO optimize it lnat_data(LNAT, LR, XLATE_TYPE, UUID_LR, State1) & lsp_link_lrp(LSP, LS, UUID_LS, LRP, LR, UUID_LR, UUID_LR_CHASSIS, State2) & (State == State1 + State2) & (State != 0) & match.eth_dst(LNAT[LNAT_XLATE_MAC], Match) & action.load(LSP[LSP_PORTID], NXM_Reg(REG_DST_IDX), Action1) & action.resubmit_next(Action2) & (Action == Action1 + Action2) ) # deliver to another lsp on local chassis lsp_lookup_dst_port(LS, Priority, Match, Action, State) <= ( (Priority == 4) & local_lsp(LSP, LS, State) & (State != 0) & match.eth_dst(LSP[LSP_MAC], Match) & action.load(LSP[LSP_PORTID], NXM_Reg(REG_DST_IDX), Action1) & action.resubmit_next(Action2) & (Action == Action1 + Action2) ) # it helps reduce time-cost _lsp_remote_lsp_changed(LSP, LS, PHY_CHASSIS, State) <= ( remote_lsp(LSP, LS, PHY_CHASSIS, State) & (State != 0)) if options.has_key('ENABLE_REDIRECT'): # output deliver to another remote chassis. # use bundle_load to check if dst chassis is dead or live. lsp_lookup_dst_port(LS, Priority, Match, Action, State) <= ( (Priority == 3) & _lsp_remote_lsp_changed(LSP, LS, PHY_CHASSIS, State) & match.eth_dst(LSP[LSP_MAC], Match) & action.load(LSP[LSP_PORTID], NXM_Reg(REG_DST_IDX), Action1) & action.bundle_load(NXM_Reg(REG_OUTPORT_IDX), [PHY_CHASSIS[PCH_OFPORT]], Action2) & # if we want output this packet in next step, we set 1->reg5 # in next step flow, no need to clean this reg5, because # it should output a port means the end of packet process action.load(1, NXM_Reg(REG5_IDX), Action3) & action.resubmit_next(Action4) & (Action == Action1 + Action2 + Action3 + Action4) ) else: # deliver to remote chassis by using output,(set outport to reg4) lsp_lookup_dst_port(LS, Priority, Match, Action, State) <= ( (Priority == 3) & _lsp_remote_lsp_changed(LSP, LS, PHY_CHASSIS, State) & match.eth_dst(LSP[LSP_MAC], Match) & action.load(LSP[LSP_PORTID], NXM_Reg(REG_DST_IDX), Action1) & action.load(PHY_CHASSIS[PCH_OFPORT], NXM_Reg(REG_OUTPORT_IDX), Action2) & # if we want output this packet in next step, we set 1->reg5 # in next step flow, no need to clean this reg5, because # it should output a a port means the end of packet process action.load(1, NXM_Reg(REG5_IDX), Action3) & action.resubmit_next(Action4) & (Action == Action1 + Action2 + Action3 + Action4) ) # deliver the packet which not match above flow to the patchport # patch port's ip address should be 255.255.255.255 lsp_lookup_dst_port(LS, Priority, Match, Action, State) <= ( (Priority == 2) & local_patchport(LSP, LS, State) & (State != 0) & match.match_none(Match) & action.load(LSP[LSP_PORTID], NXM_Reg(REG_DST_IDX), Action1) & action.resubmit_table(TABLE_LSP_EGRESS_FIRST, Action2) & (Action == Action1 + Action2) ) if options.has_key('ONDEMAND'): # ovs must upload this packet to controller if cannot found the # destination. controller will tell tuplenet to generate more flows lsp_lookup_dst_port(LS, Priority, Match, Action, State) <= ( (Priority == 0) & ls_array(LS, UUID_LS, State) & (State != 0) & match.match_none(Match) & action.upload_unknow_dst(Action1) & # resubmit this packet to next stage, gateway host can # do delivering if gateway enable redirect feature action.load(st.TP_OFPORT_NONE, NXM_Reg(REG_OUTPORT_IDX), Action2) & action.load(1, NXM_Reg(REG5_IDX), Action3) & action.resubmit_next(Action4) & (Action == Action1 + Action2 + Action3 + Action4) ) else: # deliver packet to drop table if this packet cannot # found the destination. lsp_lookup_dst_port(LS, Priority, Match, Action, State) <= ( (Priority == 0) & ls_array(LS, UUID_LS, State) & (State != 0) & match.match_none(Match) & action.resubmit_table(TABLE_DROP_PACKET, Action) ) if options.has_key('ENABLE_REDIRECT'): # if it is a redirectd packet and reg4 is 0xffff, then we should drop # it, because we don't want cause infinite loop lsp_output_dst_port(LS, Priority, Match, Action, State) <= ( (Priority == 4) & ls_array(LS, UUID_LS, State) & (State != 0) & match.reg_5(1, Match1) & match.reg_flag(FLAG_REDIRECT, Match2) & match.reg_outport(st.TP_OFPORT_NONE, Match3) & (Match == Match1 + Match2 + Match3) & action.resubmit_table(TABLE_DROP_PACKET, Action) ) # if this packet was failed to deliver to remote chassis, we send it to # other gateway to help forwarding lsp_output_dst_port(LS, Priority, Match, Action, State) <= ( (Priority == 3) & ls_array(LS, UUID_LS, State) & (State != 0) & match.reg_5(1, Match1) & match.reg_outport(st.TP_OFPORT_NONE, Match2) & (Match == Match1 + Match2) & action.resubmit_table(TABLE_REDIRECT_CHASSIS, Action) ) # output to a port base on reg4's value lsp_output_dst_port(LS, Priority, Match, Action, State) <= ( (Priority == 2) & ls_array(LS, UUID_LS, State) & (State != 0) & match.reg_5(1, Match) & action.resubmit_table(TABLE_EMBED2_METADATA, Action1) & action.resubmit_table(TABLE_OUTPUT_PKT, Action2) & (Action == Action1 + Action2) ) # just deliver to next stage lsp_output_dst_port(LS, Priority, Match, Action, State) <= ( (Priority == 1) & ls_array(LS, UUID_LS, State) & (State != 0) & match.match_none(Match) & action.resubmit_table(TABLE_LSP_EGRESS_FIRST, Action) )
action.move(NXM_Reg(TUN_ID_IDX, 0, 23), NXM_Reg(REG_DP_IDX, 0, 23), Action1) & action.move(NXM_Reg(TUN_METADATA0_IDX, 0, 15), NXM_Reg(REG_SRC_IDX, 0, 15), Action2) & action.move(NXM_Reg(TUN_METADATA0_IDX, 16, 31), NXM_Reg(REG_DST_IDX, 0, 15), Action3) & action.move(NXM_Reg(TUN_METADATA0_IDX, 32, 63), NXM_Reg(REG_FLAG_IDX, 0, 31), Action4) & (Action == Action1 + Action2 + Action3 + Action4) ) pipeline_forward(Priority, Match, Action) <= ( (Priority == 1) & match.ip_proto(Match1) & # a ip packet with 00 macaddress means it was a redirect packet which # send out by other host, deliver this packet to LR to help redirect match.eth_dst("00:00:00:00:00:00", Match2) & match.reg_flag(FLAG_REDIRECT, Match3) & (Match == Match1 + Match2 + Match3) & # TABLE_LRP_INGRESS_FIRST table is a tracing-point # as well and dec_ttl, skip that table action.resubmit_table(TABLE_LRP_INGRESS_IP_ROUTE, Action) ) # it is a regular packet, foward to lsp egress table immediately pipeline_forward(Priority, Match, Action) <= ( (Priority == 0) & match.match_none(Match) & action.resubmit_table(TABLE_LSP_EGRESS_FIRST, Action) )