/* NAT_macros.uc - Microassembly macros used with NAT */ /*********************************************************************/ /* Macro to read source and destination ports from UDP or TCP packet */ /*********************************************************************/ #macro read_src_and_dst_ports(callsite,hdr_len,IpProt,SrcPort,DstPort) .begin .reg buf_offset sdram_offset pkt_offset /* assume no IP options */ .if (IpProt == IPT_ICMP) #if (streq(callsite,'NON_LOCAL_SRC')) alu[DstPort,--,b,*l$index0[6],>>16] alu[SrcPort,0xFF,and,*l$index0[5],>>24] #else alu[SrcPort,--,b,*l$index0[6],>>16] alu[DstPort,0xFF,and,*l$index0[5],>>24] #endif .else alu[SrcPort,--,b,*l$index0[5],>>16] ld_field_w_clr[DstPort,0011,*l$index0[5]] .endif .end #endm /*********************************************************************/ /* Macro to do NAT lookup for packet with local src */ /*********************************************************************/ #macro nat_lookup_outgoing(ip_addr_loc,lport,ip_addr_rem,\\\\ rport,prot,nport,if_out) .begin .reg cnt tmp offset entry_w1 tm_offset $timer_bm .sig hash_done read_done write_done xbuf_alloc[$hash128_w,4,read_write] /* hash IP address, port and protocol */ alu[$hash128_w0,--,b,ip_addr_rem] alu[$hash128_w1,--,b,ip_addr_loc] alu[entry_w1,rport,or,lport,<<16] alu[$hash128_w2,--,b,entry_w1] alu[$hash128_w3,--,b,prot] hash_128[$hash128_w0,1], sig_done[hash_done] alu[cnt,--,b,zero] alu[nport,--,~b,zero] ctx_arb[hash_done] /* compute the hash value mod the number of buckets */ /* in the hash table */ alu[offset,$hash128_w0,and,nat_tab_bit_mask] /* computer byte offset into NAT table */ alu[offset,--,b,offset,<>16] alu[--,tmp,xor,prot] /* Check protocol */ bne[search_start#],defer[3] alu[tm_offset,--,b,offset,>>4] alu[tmp,tm_offset,and,3] alu[--,$$entry_w1,xor,entry_w1] /* Check ports */ bne[search_start#],defer[3] alu[tmp,--,b,tmp,<<3] alu[tmp,31,-,tmp] alu[--,$$entry_w2,xor,ip_addr_loc] /* Check local IP */ bne[search_start#],defer[3] alu[--,tmp,or,zero] /* dummy instruction for */ /* indirect shift */ alu[$timer_bm,--,b,one,<>16] alu[--,tmp,xor,prot] /* Check protocol */ bne[search_start#],defer[3] alu[tm_offset,--,b,offset,>>4] alu[port_tmp,0,+16,$$entry_w1] alu[--,port_tmp,xor,rport] /* Check remote port */ bne[search_start#],defer[3] alu[tmp,tm_offset,and,3] alu[port_tmp,0,+16,$$entry_w0] /* Check NAT (destination) port */ alu[--,port_tmp,xor,nport] bne[search_start#],defer[3] alu[tmp,--,b,tmp,<<3] alu[tmp,31,-,tmp] alu[--,$$entry_w3,xor,ip_addr_rem] /* Check remote IP */ bne[search_start#],defer[2] alu[--,tmp,or,zero] /* Dummy instruction for */ /* indirect shift */ alu[$timer_bm,--,b,one,<>16] ctx_arb[write_done] search_done#: .end #endm /*********************************************************************/ /* Macro to read Ethernet and IP headers from DRAM */ /*********************************************************************/ #macro eth_iphdr_load(buf_handle, req_sig) .begin .reg sdram_offset buf_offset /* Read 40 bytes of ETH/IP Header from DRAM */ /* (DRAM reads are in quadwords -- 8 bytes */ dl_buf_get_data[sdram_offset, buf_handle] dl_meta_get_offset[buf_offset] dram[read,$$iphdr0,sdram_offset,buf_offset,5],sig_done[req_sig] ctx_arb[req_sig] .end #endm /*********************************************************************/ /* Macro to write modified Ethernet and IP headers from Local */ /* memory back into DRAM */ /*********************************************************************/ #macro eth_iphdr_store(sdram_offset, buf_offset, req_sig) byte_align_be[--,eth_ipt] byte_align_be[$$iphdr3,*l$index0[0]] byte_align_be[$$iphdr4,*l$index0[1]] byte_align_be[$$iphdr5,*l$index0[2]] byte_align_be[$$iphdr6,*l$index0[3]] byte_align_be[$$iphdr7,*l$index0[4]] byte_align_be[$$iphdr8,*l$index0[5]] byte_align_be[$$iphdr9,*l$index0[6]] dram[write,$$iphdr0,sdram_offset,buf_offset,5],sig_done[req_sig] #endm /*********************************************************************/ /* Macro to update IP checksum */ /* cksum_new = cksum_old + old_val + ~new_val */ /*********************************************************************/ #macro cksum_upd(cksum,old_val,new_val) .begin .reg x not_new_val alu[x,--,b,old_val,>>16] alu[cksum,cksum,+,x] alu[cksum,cksum,+16,old_val] alu[not_new_val,--,~b,new_val] alu[x,--,b,not_new_val,>>16] alu[cksum,cksum,+,x] alu[cksum,cksum,+16,not_new_val] .end #endm /*********************************************************************/ /* Macro to add carry into checksum */ /* cksum = cksum>>16 + cksum&0xffff */ /* cksum = cksum>>16 + cksum&0xffff */ /*********************************************************************/ #macro cksum_carry(cksum) .begin .reg x alu[x,--,b,cksum,>>16] alu[cksum,x,+16,cksum] alu[x,--,b,cksum,>>16] alu[cksum,x,+16,cksum] .end #endm /*********************************************************************/ /* Macro to modify and store Eth frame header, IP packet header */ /* and UDP, TCP, or ICMP packet header */ /*********************************************************************/ #macro modify_and_save_packet_header(if_out,EthDstW0,EthDstW1,IpHlen,\\\\ IpProt,IpSrc,IpDst,SrcPort,DstPort) .begin .reg tmp cksum buf_offset pkt_offset sdram_offset .reg if_ip if_eth_w0 if_eth_w1 oldId oldPorts oldIpSrc oldIpDst .sig dram_rd dram_wr1 dram_wr2 /* Compute sdram offset for the buffer */ dl_buf_get_data[sdram_offset, dl_buf_handle] /* Set the Ethernet header */ net_if_data_get(if_out,if_ip,if_eth_w0,if_eth_w1) alu[$$iphdr0,--,b,EthDstW0] alu[$$iphdr1,EthDstW1,or,if_eth_w0,>>16] dbl_shf[$$iphdr2,if_eth_w0,if_eth_w1,>>16] /* Update the IP header */ ld_field_w_clr[cksum,0011,*l$index0[2]] alu[oldIpSrc,--,b,*l$index0[3]] alu[oldIpDst,--,b,*l$index0[4]] /* Calculate new checksum */ cksum_upd(cksum,oldIpSrc,IpSrc) cksum_upd(cksum,oldIpDst,IpDst) cksum_carry(cksum) /* Save the new checksum and IP addresses */ ld_field[*l$index0[2],0011,cksum] alu[*l$index0[3],--,b,IpSrc] alu[*l$index0[4],--,b,IpDst] /* Update the TCP, UDP, or ICMP header. Note: we assume that */ /* the datagram does not contain IP options */ .if (IpProt == IPT_ICMP) /* Update the ICMP header */ ld_field_w_clr[cksum,0011,*l$index0[5]] alu[oldId,--,b,*l$index0[6],>>16] .if (IpSrc == NAT_ip) cksum_upd(cksum,oldId,SrcPort) ld_field[*l$index0[6],1100,SrcPort,<<16] .else cksum_upd(cksum,oldId,DstPort) ld_field[*l$index0[6],1100,DstPort,<<16] .endif cksum_carry(cksum) ld_field[*l$index0[5],0011,cksum] dl_meta_get_offset[buf_offset] /* Save the modified Ethernet and IP headers */ eth_iphdr_store(sdram_offset,buf_offset,dram_wr1) .else /* Update the TCP or UDP header */ dl_meta_get_offset[buf_offset] .if (IpProt == IPT_TCP) alu[pkt_offset,buf_offset,+,48] .else alu[pkt_offset,buf_offset,+,40] .endif /* Read the old UDP or TCP checksum */ dram[read,$$pkt_hdr0,sdram_offset,pkt_offset,1], sig_done[dram_rd] alu[oldPorts,--,b,*l$index0[5]] alu[*l$index0[5],DstPort,or,SrcPort,<<16] /* Save the modified Ethernet and IP headers */ eth_iphdr_store(sdram_offset,buf_offset,dram_wr1) /* Wait for the checksum to be read */ ctx_arb[dram_rd] .if (IpProt == IPT_TCP) ld_field_w_clr[cksum,0011,$$pkt_hdr0] .else alu[cksum,--,b,$$pkt_hdr0,>>16] /* If UDP checksum is 0, no update needed */ alu[--,cksum,xor,zero] bne[wait#] .endif cksum_upd(cksum,oldIpSrc,IpSrc) cksum_upd(cksum,oldIpDst,IpDst) alu[tmp,DstPort,or,SrcPort,<<16] cksum_upd(cksum,oldPorts,tmp) cksum_carry(cksum) .if (IpProt == IPT_TCP) alu[tmp,--,b,cksum] ld_field[tmp,1100,$$pkt_hdr0] .else alu[tmp,--,b,cksum,<<16] ld_field[tmp,0011,$$pkt_hdr0] .endif alu[$$pkt_hdr0,--,b,tmp] alu[$$pkt_hdr1,--,b,$$pkt_hdr1] dram[write,$$pkt_hdr0,sdram_offset,pkt_offset,1], sig_done[dram_wr2] ctx_arb[dram_wr1,dram_wr2],br[done#] .endif wait#: ctx_arb[dram_wr1] done#: .end #endm /*********************************************************************/ /* Macro to obtain a copy of network interface settings */ /*********************************************************************/ #macro net_if_data_get(ifnum,if_ip,if_eth_w0,if_eth_w1) alu[temp,--,b,ifnum,<<3] jump[temp, if_0#], targets[if_0#,if_1#] /* set network interface parameters */ if_0#: immed[if_ip, IF0_IP] immed_w1[if_ip, IF0_IP>>16] immed[if_eth_w0,IF0_ETH_W0] immed_w1[if_eth_w0,IF0_ETH_W0>>16] br[end_of_if_table#],defer[2] immed[if_eth_w1,IF0_ETH_W1] immed_w1[if_eth_w1,IF0_ETH_W1>>16] nop /* added for alignment */ if_1#: immed[if_ip, IF1_IP] immed_w1[if_ip, IF1_IP>>16] immed[if_eth_w0,IF1_ETH_W0] immed_w1[if_eth_w0,IF1_ETH_W0>>16] immed[if_eth_w1,IF1_ETH_W1] immed_w1[if_eth_w1,IF1_ETH_W1>>16] end_of_if_table#: #endm /*********************************************************************/ /* Macro to perform ARP table lookup */ /*********************************************************************/ #macro arp_lookup(port,IpDst,EthAddrW0,EthAddrW1) .begin .reg ip_addr cnt tmp offset $hash48_w0 $hash48_w1 .reg $entry_w0 $entry_w1 $entry_w2 .sig hash_done read_done .xfer_order $hash48_w0 $hash48_w1 .xfer_order $entry_w0 $entry_w1 $entry_w2 .if (port == NAT_IFC) alu[ip_addr,--,b,gateway_ip] .else alu[ip_addr,--,b,IpDst] .endif /* Hash the IP address */ alu[$hash48_w0,--,b,ip_addr] alu[$hash48_w1,--,b,zero] hash_48[$hash48_w0,1], sig_done[hash_done] alu[cnt,--,b,zero] ctx_arb[hash_done] /* Compute the hash value mod the size of the ARP table */ alu[offset,$hash48_w0,and,arp_tab_bit_mask] /* Compute the byte offset into the ARP table */ alu[offset,--,b,offset,<<4] /* Adjust the start of the table */ alu[offset,offset,-,16] /* Search the table sequentially */ arp_search_start#: alu[--,arp_tab_bit_mask,-,cnt] blt[exception#] /* lookup failed */ alu[offset,offset,+,16] alu[offset,offset,and,arp_tab_bit_mask,<<4] sram[read,$entry_w0,arp_tab,offset,3],ctx_swap[read_done] alu[--,$entry_w0,xor,ip_addr] bne[arp_search_start#],defer[1] alu[cnt,cnt,+,one] br_bclr[$entry_w2,0,arp_search_start#] arp_search_end#: /* Set the word 0 of the Ethernet address */ alu[EthAddrW0,--,b,$entry_w1] /* Set word 1 of the Ethernet address */ ld_field_w_clr[EthAddrW1,1100,$entry_w2] /* Set the output port */ ld_field_w_clr[if_out,0011,$entry_w2,>>1] .end #endm /*********************************************************************/ /* Macro to write the current packet on the TX ring */ /*********************************************************************/ #macro write_tx_ring(ring_num,label) #define_eval RN PACKET_TX_SCR_RING_/**/ring_num br_inp_state[SCR_RING/**/RN/**/_FULL, full_ring/**/ring_num/**/#] scratch[put,$txreq,zero,(RN<<2),1],sig_done[sig_scr_put] ctx_arb[sig_scr_put],br[label] nop #endm