Index: /branches/rel_apv_10_7/usr/click/lib/libkernelapi/addCommands.pm
===================================================================
--- /branches/rel_apv_10_7/usr/click/lib/libkernelapi/addCommands.pm	(revision 39536)
+++ /branches/rel_apv_10_7/usr/click/lib/libkernelapi/addCommands.pm	(working copy)
@@ -2307,6 +2307,21 @@
     },
     {
         cmd_attribute => "CMD_KERN_API",
+        function_name => "nat_protocol_dns_priority_kern",
+        function_args => [
+                            {type => "STRING"},
+                            {type => "U32"},
+                        ]
+    },
+    {
+        cmd_attribute => "CMD_KERN_API",
+        function_name => "no_nat_protocol_dns_priority_kern",
+        function_args => [
+                            {type => "STRING"},
+                        ],
+    },
+    {
+        cmd_attribute => "CMD_KERN_API",
         function_name => "clear_nat_protocol_dns_kern",
         function_args => [],
     },
@@ -2327,6 +2342,11 @@
         function_name => "clear_nat_dns_status_kern",
         function_args => [],
     },
+    {
+        cmd_attribute => "CMD_KERN_API",
+        function_name => "clear_nat_dns_priority_kern",
+        function_args => [],
+    },
 # check_nat_static_kern add by donghy 20041117 for bug 7565
     {
         cmd_attribute => "CMD_KERN_API",
Index: /branches/rel_apv_10_7/usr/click/lib/libnatd_cli/natd_cli.c
===================================================================
--- /branches/rel_apv_10_7/usr/click/lib/libnatd_cli/natd_cli.c	(revision 39536)
+++ /branches/rel_apv_10_7/usr/click/lib/libnatd_cli/natd_cli.c	(working copy)
@@ -946,6 +946,18 @@
 }
 
 int 
+nat_protocol_dns_priority(char *vip, uint32_t priority)
+{
+	return nat_protocol_dns_priority_kern(vip, priority);
+}
+
+int 
+no_nat_protocol_dns_priority(char *vip)
+{
+	return no_nat_protocol_dns_priority_kern(vip);
+}
+
+int 
 clear_nat_protocol_dns()
 {
 	return clear_nat_protocol_dns_kern();
@@ -969,3 +981,8 @@
 	return clear_nat_dns_status_kern();
 }
 
+int 
+clear_nat_dns_priority()
+{
+	return clear_nat_dns_priority_kern();
+}
Index: /branches/rel_apv_10_7/usr/click/lib/libparser/commands.pm
===================================================================
--- /branches/rel_apv_10_7/usr/click/lib/libparser/commands.pm	(revision 39536)
+++ /branches/rel_apv_10_7/usr/click/lib/libparser/commands.pm	(working copy)
@@ -34226,11 +34226,32 @@
         function_name => "nat_protocol_dns",
 		function_args => [ {
 				type => "STRING",
-				help_string => "DNS NAT method, the value must be rr or proximity. The default value is proximity.",
+				help_string => "DNS NAT method, the value must be rr, priority or proximity. The default value is proximity.",
 				optional => "YES",
 				default_value => "\"proximity\"",
 				}, ],
 	},
+    {
+        obj_type => "ITEM",
+        name => "dnspri",
+        menu => "root_nat",
+        help_string => "Set NAT static entry priority for DNS response rewriting (priority mode only)",
+        cmd_attribute => "CMD_ARRAYOS|CMD_SPROXY|CMD_NORMAL|CMD_GLOBAL",
+        user_level => "CLI_LEVEL_CONFIG",
+        function_name => "nat_protocol_dns_priority",
+        function_args => [ 
+            {
+                type => "IPADDR",
+                help_string => "Virtual IP to masquerade as",
+                optional => "NO",
+            },
+            {
+                type => "U32",
+                help_string => "Specify the priority, in range [1, 512]",
+                optional => "NO",
+            },
+        ]
+    },
 	{
 		obj_type => "MENU",
 		name => "pureip",
@@ -34541,6 +34562,22 @@
 		function_args => [],
     },
     {
+        obj_type => "ITEM",
+        name => "dnspri",
+        menu => "root_nat_no",
+        help_string => "Stop NAT DNS response rewriting (priority mode only)",
+        cmd_attribute => "CMD_ARRAYOS|CMD_SPROXY|CMD_NORMAL|CMD_GLOBAL",
+        user_level => "CLI_LEVEL_CONFIG",
+        function_name => "no_nat_protocol_dns_priority",
+        function_args => [
+                            {
+                                type => "IPADDR",
+                                help_string => "Outside IP for which the static NAT is to be stopped",
+                                optional => "NO",
+                            }
+                        ]
+    },
+    {
 	    obj_type => "MENU",
 	    name => "protocol",
 	    parent_menu => "root_nat_clear",
@@ -34597,6 +34634,16 @@
 				function_name => "clear_nat_dns_status",
 				function_args => [],
 	},
+    {
+        obj_type => "ITEM",
+        name => "priority",
+        menu => "root_clear_nat_dns",
+        help_string => "Stop all NAT DNS response rewriting (priority mode only)",
+        cmd_attribute => "CMD_ARRAYOS|CMD_SPROXY|CMD_NORMAL|CMD_GLOBAL",
+        user_level => "CLI_LEVEL_CONFIG",
+        function_name => "clear_nat_dns_priority",
+        function_args => [],
+    },
 	{
 		obj_type => "MENU",
 		name => "itcpopt",
Index: /branches/rel_apv_10_7/usr/src/sys/click/app/dns/dns.c
===================================================================
--- /branches/rel_apv_10_7/usr/src/sys/click/app/dns/dns.c	(revision 39536)
+++ /branches/rel_apv_10_7/usr/src/sys/click/app/dns/dns.c	(working copy)
@@ -2226,6 +2226,68 @@
 	return NULL;
 }
 
+static int
+nat_dns_priority_cmp(const void *ap, const void *bp)
+{
+	const nat_table *cp = *(const nat_table * const *)ap;
+	const nat_table *dp = *(const nat_table * const *)bp;
+	return cp->nat_dns_pri - dp->nat_dns_pri;
+}
+
+static nat_table * 
+dns_get_nat_priority(int isipv6, nat_dns_table *nat_dns_info)
+{
+	nat_table *nat_conf_p;
+	nat_table *sort_table[MAX_NATS];
+	struct llb_link *link = NULL;
+	int i, len = 0;
+
+	if (nat_dns_info == NULL) {
+		return NULL;
+	}
+
+	if (isipv6) {
+		TAILQ_FOREACH(nat_conf_p, &nat6_static_conf_list, conf_link) {
+			if (IN6_ARE_ADDR_EQUAL(&nat_conf_p->network6, &nat_dns_info->first_nat_conf->network6) && nat_conf_p->nat_dns_pri != 0) {
+				sort_table[len++] = nat_conf_p;
+			}
+		}
+	} else {
+		TAILQ_FOREACH(nat_conf_p, &nat_static_conf_list, conf_link) {		
+			if (nat_conf_p->network == nat_dns_info->first_nat_conf->network && nat_conf_p->nat_dns_pri != 0) {
+				sort_table[len++] = nat_conf_p;
+			}
+		}
+	}
+
+	qsort(sort_table, len, sizeof(nat_table *), nat_dns_priority_cmp);
+
+	for(i = 0; i < len; i++)
+	{
+		nat_conf_p = sort_table[i];
+
+		if (isipv6) {
+			if (!IN6_IS_ADDR_UNSPECIFIED(&nat_conf_p->gw6)) {
+				link = search_llb_link_by_gwip(&link_queue, (void*)&nat_conf_p->gw6, isipv6);
+			} else {
+				link = search_llb_link_by_ip(&link_queue, (void*)&nat_conf_p->ip6, isipv6);
+			}
+		} else {
+			if (nat_conf_p->gw) {
+				link = search_llb_link_by_gwip(&link_queue, (void*)&nat_conf_p->gw, isipv6);
+			} else {
+				link = search_llb_link_by_ip(&link_queue, (void*)&nat_conf_p->ip, isipv6);
+			}
+		}
+
+		if (!link || HC_GW_UP(link)) {
+			return nat_conf_p;
+		}
+	}
+
+	return NULL;
+}
+
 static nat_table * 
 dns_get_nat_wrr(int isipv6, nat_dns_table *nat_dns_info)
 {
@@ -2329,6 +2391,13 @@
 		}
 	}
 
+	if (nat_dns_conf.method == NAT_DNS_PRIORITY) {
+		nat_conf_p = dns_get_nat_priority(isipv6, nat_dns_info);
+		if (nat_conf_p == NULL) {
+			return 0;
+		}
+	}
+
 	if (nat_conf_p == NULL) {
 		nat_conf_p = dns_get_nat_wrr(isipv6, nat_dns_info);
 		if (nat_conf_p == NULL) {
Index: /branches/rel_apv_10_7/usr/src/sys/netinet/ip_canat.h
===================================================================
--- /branches/rel_apv_10_7/usr/src/sys/netinet/ip_canat.h	(revision 39536)
+++ /branches/rel_apv_10_7/usr/src/sys/netinet/ip_canat.h	(working copy)
@@ -43,6 +43,9 @@
 #define RST_ID_NAT1     (RST_APP_ID_NAT+1)
 #define NAT_DESCRIPTION_LEN	32
 
+#define NAT_DNS_PRIORITY_MIN    1
+#define NAT_DNS_PRIORITY_MAX    512
+
 typedef enum NAT_STAT_PRO
 {
     NAT_STAT_ICMP,
@@ -141,6 +144,7 @@
 	/* for nat dns */
 	int nat_dns_hits[ATCP_MAXTHREADS];
 	int is_nat_dns;
+	uint32_t nat_dns_pri;
 	/* for nat dns */
 } nat_table;
 #define nattimer timer[curatcp]
@@ -213,6 +217,7 @@
 enum {
 	NAT_DNS_RR,
 	NAT_DNS_PROXIMITY,
+	NAT_DNS_PRIORITY,
 	NAT_DNS_METHOD_MAX,
 };
 typedef struct _nat_dns_config {
@@ -230,6 +235,7 @@
 extern nat_dns_config nat_dns_conf;
 #define NAT_DNS_RR_STR			("rr")
 #define NAT_DNS_PROXIMITY_STR	("proximity")
+#define NAT_DNS_PRIORITY_STR	("priority")
 #define nat_dns_is_on()			(nat_dns_conf.enable == 1)
 nat_dns_table *nat_dns_get(int isipv6, void *ip_inside);
 /* for nat dns */
Index: /branches/rel_apv_10_7/usr/src/sys/netinet/ip_canat_kern.c
===================================================================
--- /branches/rel_apv_10_7/usr/src/sys/netinet/ip_canat_kern.c	(revision 39536)
+++ /branches/rel_apv_10_7/usr/src/sys/netinet/ip_canat_kern.c	(working copy)
@@ -109,7 +109,7 @@
 nat_dns_table_list_t nat6_dns_info_list[ATCP_MAXTHREADS];
 nat_dns_table nat_dns_table_array[ATCP_MAXTHREADS][MAX_NATS];
 nat_dns_config nat_dns_conf = { 0, NAT_DNS_PROXIMITY };		/* default enable=0, method=proximity */
-static const char *nat_dns_method[NAT_DNS_METHOD_MAX] = {NAT_DNS_RR_STR, NAT_DNS_PROXIMITY_STR};
+static const char *nat_dns_method[NAT_DNS_METHOD_MAX] = {NAT_DNS_RR_STR, NAT_DNS_PROXIMITY_STR, NAT_DNS_PRIORITY_STR};
 static int nat_static_update_for_dns();
 static void nat_dns_table_clear();
 /* for nat dns */
@@ -555,7 +555,6 @@
 		}
 	}
 
-
 	/* write ipv6 nat dst group list */	
 	TAILQ_FOREACH(nat_conf_p, &nat6_dst_group_list, conf_link) {
 		for (nat_following_p = nat_conf_p; nat_following_p != NULL; nat_following_p = nat_following_p->following) {
@@ -567,7 +566,24 @@
 				nat_following_p->timeout/hz, gw_str, nat_following_p->description);
 		}
 	}
-	
+
+	/* write v4 nat dnspri */	
+	TAILQ_FOREACH(nat_conf_p, &nat_static_conf_list, conf_link) {
+		if (nat_conf_p->nat_dns_pri) {
+			vip_addr.s_addr = nat_conf_p->ip;
+			strncpy(vip_str, inet_ntoa(vip_addr), 16);
+			cur += sprintf(cur,"nat dnspri %s %d\n", vip_str, nat_conf_p->nat_dns_pri);			
+		}
+	}
+
+	/* write v6 nat dnspri */	
+	TAILQ_FOREACH(nat_conf_p, &nat6_static_conf_list, conf_link) {
+		if (nat_conf_p->nat_dns_pri) {
+			inet_ntop(AF_INET6, &nat_conf_p->ip6, vip_str, INET6_ADDRSTRLEN);
+			cur += sprintf(cur,"nat dnspri %s %d\n", vip_str, nat_conf_p->nat_dns_pri);
+		}
+	}
+
 	/* Bug 21930, chengfei, 20090413*/
 	if (pptp_gre_inbound_enabled){
 		cur += sprintf(cur, "nat protocol pptp %d \"inbound\"\n", pptp_gre_inbound_port);
@@ -1362,6 +1378,7 @@
 	strcpy(nat_conf_newp->description, description);
 	nat_conf_newp->following = NULL;
 	nat_conf_newp->sn = sn++;
+	nat_conf_newp->nat_dns_pri = 0;
 	/* Initialize the nat_conf timer and put it into the global timver list. */
 	for (j = 0; j < atcp_nthreads; j++) {
 		curatcp = j;
@@ -2877,14 +2894,16 @@
 		nat_dns_method = NAT_DNS_RR;
 	} else if (strcmp(method, NAT_DNS_PROXIMITY_STR) == 0) {
 		nat_dns_method = NAT_DNS_PROXIMITY;
+	} else if (strcmp(method, NAT_DNS_PRIORITY_STR) == 0) {
+		nat_dns_method = NAT_DNS_PRIORITY;
 	} else {
-		app_printf(pcb, "Invalid DNS NAT method, the value must be rr or proximity.\n");
+		app_printf(pcb, "Invalid DNS NAT method, the value must be rr, priority or proximity.\n");
 		return -1;
 	}
 	
 	nat_dns_conf.method = nat_dns_method;
 	nat_dns_conf.enable = 1;
-	
+
 	return 0;
 }
 
@@ -2902,6 +2921,91 @@
 }
 
 int 
+nat_protocol_dns_priority_kern(void *pcb, char *ip, uint32_t priority)
+{
+	nat_table *nat_conf_p;
+	click_ip_t vip;
+
+	if (priority < NAT_DNS_PRIORITY_MIN || priority > NAT_DNS_PRIORITY_MAX) {
+		app_printf(pcb, "Priority must be in the range of [%d , %d]\n", NAT_DNS_PRIORITY_MIN, NAT_DNS_PRIORITY_MAX);
+		return -1;
+	}
+
+	if (IS_IP6_ADDRESS(ip)) {
+		vip.isipv6 = 1;
+		inet_pton(AF_INET6, ip, &vip.addr.ip6);
+	} else {
+		vip.isipv6 = 0;
+		inet_pton(AF_INET, ip, &vip.addr.ip4);
+	}
+
+	/* 1. find the item */
+	if (vip.isipv6) {
+		TAILQ_FOREACH(nat_conf_p, &nat6_static_conf_list, conf_link) {
+			if (IN6_ARE_ADDR_EQUAL(&nat_conf_p->ip6, &vip.addr.ip6)) {
+				break;
+			}
+		}
+	} else {
+		TAILQ_FOREACH(nat_conf_p, &nat_static_conf_list, conf_link) {
+			if (nat_conf_p->ip == vip.addr.ip4.s_addr) {
+				break;
+			}
+		}
+	}
+
+	if(nat_conf_p == NULL) {
+		app_printf(pcb, "The NAT item is not configured.\n");
+		return -1;
+	}
+
+	/* 2. update the priority */
+	nat_conf_p->nat_dns_pri = priority;
+
+	return 0;
+}
+
+int 
+no_nat_protocol_dns_priority_kern(void *pcb, char *ip)
+{
+	nat_table *nat_conf_p;
+	click_ip_t vip;
+
+	if (IS_IP6_ADDRESS(ip)) {
+		vip.isipv6 = 1;
+		inet_pton(AF_INET6, ip, &vip.addr.ip6);
+	} else {
+		vip.isipv6 = 0;
+		inet_pton(AF_INET, ip, &vip.addr.ip4);
+	}
+
+	/* 1. find the item */
+	if (vip.isipv6) {
+		TAILQ_FOREACH(nat_conf_p, &nat6_static_conf_list, conf_link) {
+			if (IN6_ARE_ADDR_EQUAL(&nat_conf_p->ip6, &vip.addr.ip6)) {
+				break;
+			}
+		}
+	} else {
+		TAILQ_FOREACH(nat_conf_p, &nat_static_conf_list, conf_link) {
+			if (nat_conf_p->ip == vip.addr.ip4.s_addr) {
+				break;
+			}
+		}
+	}
+
+	if(nat_conf_p == NULL) {
+		app_printf(pcb, "The NAT item is not configured.\n");
+		return -1;
+	}
+
+	/* 2. reset the priority */
+	nat_conf_p->nat_dns_pri = 0;
+
+	return 0;
+}
+
+int 
 clear_nat_protocol_dns_kern(void *pcb)
 {
 	no_nat_protocol_dns_kern(pcb);
@@ -2999,6 +3103,27 @@
 
 	return 0;
 }
+
+int 
+clear_nat_dns_priority_kern(void *pcb)
+{
+	nat_table *nat_conf_p = NULL;
+
+	TAILQ_FOREACH(nat_conf_p, &nat6_static_conf_list, conf_link) {
+		if (nat_conf_p->nat_dns_pri) {
+			nat_conf_p->nat_dns_pri = 0;
+		}
+	}
+
+	TAILQ_FOREACH(nat_conf_p, &nat_static_conf_list, conf_link) {
+		if (nat_conf_p->nat_dns_pri) {
+			nat_conf_p->nat_dns_pri = 0;
+		}
+	}
+
+	return 0;
+}
+
 /* for nat dns */
 
 int 
