Index: /branches/rel_apv_10_7/usr/src/sys/click/netinet/click_input.c
===================================================================
--- /branches/rel_apv_10_7/usr/src/sys/click/netinet/click_input.c	(revision 39217)
+++ /branches/rel_apv_10_7/usr/src/sys/click/netinet/click_input.c	(working copy)
@@ -18537,6 +18537,8 @@
 		return 0;
 	} else {
 		struct eroute_rule *eroute_rule = NULL;
+		nat_table *nat_conf_p = NULL;
+		void *dd_egroup_p = NULL;
 		int proto_id = 0;
 		if (dpi_on) {
 			eroute_rule = click_dpi_input(m, isipv6, &proto_id);
@@ -18546,7 +18548,9 @@
 			if (BRIDGE_MBUF_IS_BRIDGE(m) && !isipv6) {
 				eroute_rule = bridge_flowtable_search(m);
 				/* The following code will do error handling (eroute_rule == NULL)  */
-			} else { 	
+			} else if (!(nat_conf_p = is_nat(m, isipv6, ip, &eroute_rule, &dd_egroup_p))) {
+				/* TWSD-196, if there is a NAT entry, `nat_conf_p`, match the packet's tuple, `eroute_rule` will be updated.
+				If not, run below code*/
 				if (IS_SEGMENT_ENABLE() && 
 					(m->m_flags & M_PKTHDR) && 
 					(m->m_pkthdr.rcvif != NULL) && 
@@ -18564,7 +18568,28 @@
 		}
 		
 		if (eroute_rule != NULL) {
+			/* a random local port number for NAT*/
+			int localport = (random() % (portlast - portfirst + 1)) + portfirst;
 			if (isipv6){
+				ip6 = mtod(m, struct ip6_hdr *);
+				/*If NAT entry is existed, rewrite the source IP in mbuf*/
+				if (nat_conf_p){
+					ip6->ip6_src = nat_conf_p->ip6;
+					while(is_management6_port(nat_conf_p->ip6, localport)){
+						localport = (random() % (portlast - portfirst + 1)) + portfirst;
+					}
+					if (ip->ip_p == IPPROTO_UDP){
+						struct udphdr *udp = (struct udphdr *)(ip6 + 1);
+						udp->uh_sport = htons(localport);
+						clickudp6_cksum(m, IPPROTO_UDP, sizeof(struct ip6_hdr), ntohs(ip6->ip6_plen),
+							ip6, udp, ERT_IFP(eroute_rule));
+					} else if (ip->ip_p == IPPROTO_TCP){
+						struct tcphdr *tcp = (struct tcphdr *)(ip6 + 1);
+						tcp->th_sport = htons(localport);
+						clicktcp6_cksum(m, IPPROTO_TCP, sizeof(struct ip6_hdr), ntohs(ip6->ip6_plen),
+							ip6, tcp, ERT_IFP(eroute_rule));
+					}
+				}
 				clicktcp6_output(m, ERT_RTENTRY(eroute_rule),ERT_NUMA_IFP(eroute_rule), eroute_rule);
 				if (ev_debug_route){
 					printf("\n ev debug: v6 after find_eroutev()");
@@ -18577,6 +18602,25 @@
 				int mtu = ifp->if_mtu;
 				ip = mtod(m, struct ip *);
 				struct mbuf *mp = NULL;
+
+				/*If NAT entry is existed, rewrite the source IP in mbuf*/
+				if (nat_conf_p){
+					ip->ip_src.s_addr = nat_conf_p->ip;
+					while(is_management_port(nat_conf_p->ip, localport)){
+						localport = (random() % (portlast - portfirst + 1)) + portfirst;
+					}
+					if (ip->ip_p == IPPROTO_UDP){
+						struct udphdr *udp = (struct udphdr *)(ip + 1);
+						udp->uh_sport = htons(localport);
+						clickudp_udp_cksum_sw(m, ifp);
+					}
+					else if (ip->ip_p == IPPROTO_TCP){
+						struct tcphdr *tcp = (struct tcphdr *)(ip + 1);
+						tcp->th_sport = htons(localport);
+						clicktcp_tcp_cksum_sw(m, ifp);
+					}
+					clickudp_ip_cksum(m, ifp);
+				}
 				if ((ip->ip_p == IPPROTO_UDP || ip->ip_p == IPPROTO_TCP) && ntohs(ip->ip_len) > mtu) {
 					/*hardware checksum may work abormal for UDP if IP fragment happened*/
                                         if ( ip->ip_p == IPPROTO_UDP )
@@ -18599,6 +18643,10 @@
 									(uint16_t)((ntohs(ip->ip_off) & IP_OFFMASK)*8));
 							}
 
+							if (nat_conf_p){
+								ip = mtod(m, struct ip *);
+								ip->ip_src.s_addr = nat_conf_p->ip;
+							}
 							/*calculate ip checksum for every IP fragment*/
 							clickudp_ip_cksum(m, ifp);
 							
