Jelajahi Sumber

mtree: added mi/rpc command to match against records in memory trees

- FS#373
Seudin Kasumovic 11 tahun lalu
induk
melakukan
0620105b03

+ 44 - 8
modules/mtree/README

@@ -20,9 +20,9 @@ Juha Heinanen
 
    <[email protected]>
 
-   Copyright (c) 2010 Daniel-Constantin Mierla (asipto.com)
+   Copyright © 2010 Daniel-Constantin Mierla (asipto.com)
 
-   Copyright (c) 2011 Juha Heinanen
+   Copyright © 2011 Juha Heinanen
      __________________________________________________________________
 
    Table of Contents
@@ -60,11 +60,13 @@ Juha Heinanen
               5.1. mt_list
               5.2. mt_reload
               5.3. mt_summary
+              5.4. mt_match
 
         6. RPC Commands
 
               6.1. mtree.summary
               6.2. mtree.reload
+              6.3. mtree.match
 
    List of Examples
 
@@ -118,11 +120,13 @@ Chapter 1. Admin Guide
         5.1. mt_list
         5.2. mt_reload
         5.3. mt_summary
+        5.4. mt_match
 
    6. RPC Commands
 
         6.1. mtree.summary
         6.2. mtree.reload
+        6.3. mtree.match
 
 1. Overview
 
@@ -316,7 +320,7 @@ modparam("mtree", "mt_allow_duplicates", 1)
 
    4.1. mt_match(mtree, pv, mode)
 
-4.1.  mt_match(mtree, pv, mode)
+4.1. mt_match(mtree, pv, mode)
 
    Match 'pv' value against 'mtree'. If 'mtree' type is 0 or 2 and value
    of 'mode' is NOT 2, sets a value of the longest matching prefix to
@@ -336,8 +340,9 @@ mt_match("mytree", "$rU", "0");
    5.1. mt_list
    5.2. mt_reload
    5.3. mt_summary
+   5.4. mt_match
 
-5.1.  mt_list
+5.1. mt_list
 
    List content of a tree.
 
@@ -351,7 +356,7 @@ mt_match("mytree", "$rU", "0");
                 _mtname_
                 _empty_line_
 
-5.2.  mt_reload
+5.2. mt_reload
 
    Reload mtree from database.
 
@@ -366,7 +371,7 @@ mt_match("mytree", "$rU", "0");
                 _mtname_
                 _empty_line_
 
-5.3.  mt_summary
+5.3. mt_summary
 
    List usage summary for all trees.
 
@@ -378,21 +383,52 @@ mt_match("mytree", "$rU", "0");
                 :mt_summary:_reply_fifo_file_
                 _empty_line_
 
+5.4. mt_match
+
+   Match prefix value against mtree.
+
+   Name: mt_match
+
+   Parameters: 3
+     * Name of mtree
+     * Prefix to match
+     * Mode of matching
+
+   MI FIFO Command Format:
+                :mt_match:_reply_fifo_file_
+                _mtree_
+                _prefix_
+                _mode_
+                _empty_line_
+
 6. RPC Commands
 
    6.1. mtree.summary
    6.2. mtree.reload
+   6.3. mtree.match
 
-6.1.  mtree.summary
+6.1. mtree.summary
 
    List usage summary for all trees.
 
    Parameters: none.
 
-6.2.  mtree.reload
+6.2. mtree.reload
 
    Reload mtree from database to memory.
 
    Parameters:
      * _mtree_
        - name of mtree or empty string meaning all mtrees
+
+6.3. mtree.match
+
+   Match prefix value against mtree
+
+   Parameters:
+     * _mtree_
+       - name of mtree
+     * _prefix_
+       - match prefix
+     * _mode_
+       - matching mode

+ 48 - 0
modules/mtree/doc/mtree_admin.xml

@@ -421,6 +421,40 @@ mt_match("mytree", "$rU", "0");
 		_empty_line_
 		</programlisting>
     </section>
+
+    <section>
+		<title>
+		<function moreinfo="none">mt_match</function>
+		</title>
+		<para>
+		Match prefix value against mtree.
+		</para>
+		<para>
+		Name: <emphasis>mt_match</emphasis>
+		</para>
+		<para>Parameters: <emphasis>3</emphasis></para>
+		<itemizedlist>
+            <listitem>
+            <para><emphasis>Name of mtree</emphasis></para>
+            </listitem>
+            <listitem>
+            <para><emphasis>Prefix to match</emphasis></para>
+            </listitem>
+            <listitem>
+            <para><emphasis>Mode of matching</emphasis></para>
+            </listitem>
+        </itemizedlist>
+		<para>
+		MI FIFO Command Format:
+		</para>
+        <programlisting  format="linespecific">
+		:mt_match:_reply_fifo_file_
+		_mtree_
+		_prefix_
+		_mode_
+		_empty_line_
+		</programlisting>
+    </section>
     </section><!-- MI commands -->
 	<section>
 	<title>RPC Commands</title>
@@ -445,6 +479,20 @@ mt_match("mytree", "$rU", "0");
 			<listitem><para>_mtree_</para> - name of mtree or empty string meaning all mtrees</listitem>	  
 		</itemizedlist>
         </section>
+    <section>
+		<title>
+		<function moreinfo="none">mtree.match</function>
+		</title>
+		<para>
+		Match prefix value against mtree
+		</para>
+		<para>Parameters:</para>
+		<itemizedlist>
+			<listitem><para>_mtree_</para> - name of mtree</listitem>
+			<listitem><para>_prefix_</para> - match prefix</listitem>
+			<listitem><para>_mode_</para> - matching mode</listitem>
+		</itemizedlist>
+        </section>
     	</section><!-- RPC commands -->
 
 </chapter>

+ 420 - 4
modules/mtree/mtree.c

@@ -292,13 +292,13 @@ m_tree_t* mt_get_first_tree()
 }
 
 
-is_t* mt_get_tvalue(m_tree_t *pt, str *tomatch)
+is_t* mt_get_tvalue(m_tree_t *pt, str *tomatch, int *len)
 {
 	int l;
 	mt_node_t *itn;
 	is_t *tvalue;
 
-	if(pt==NULL || tomatch==NULL || tomatch->s==NULL)
+	if(pt==NULL || tomatch==NULL || tomatch->s==NULL || len == NULL)
 	{
 		LM_ERR("bad parameters\n");
 		return NULL;
@@ -327,6 +327,8 @@ is_t* mt_get_tvalue(m_tree_t *pt, str *tomatch)
 		l++;	
 	}
 
+	*len = l;
+
 	return tvalue;
 }
 
@@ -387,7 +389,7 @@ int mt_match_prefix(struct sip_msg *msg, m_tree_t *it,
 		str *tomatch, int mode)
 {
 	int l, len, n;
-	int i, j;
+	int i, j, k = 0;
 	mt_node_t *itn;
 	is_t *tvalue;
 	int_str dstid_avp_name;
@@ -413,7 +415,7 @@ int mt_match_prefix(struct sip_msg *msg, m_tree_t *it,
 	if ((it->type==MT_TREE_SVAL) || (it->type==MT_TREE_IVAL)) {
 		if (mode == 2) 
 			return mt_add_tvalues(msg, it, tomatch);
-		tvalue = mt_get_tvalue(it, tomatch);
+		tvalue = mt_get_tvalue(it, tomatch, &k);
 		if (tvalue == NULL) {
 			LM_DBG("no match for: %.*s\n", tomatch->len, tomatch->s);
 			return -1;
@@ -873,3 +875,417 @@ int mt_defined_trees(void)
 	return 0;
 }
 
+int mt_mi_add_tvalues(struct mi_node *rpl, m_tree_t *pt, str *tomatch)
+{
+	int l;
+	mt_node_t *itn;
+	mt_is_t *tvalues;
+	struct mi_attr* attr= NULL;
+	struct mi_node *node = NULL;
+
+	if (pt == NULL || tomatch == NULL || tomatch->s == NULL) {
+		LM_ERR("bad parameters\n");
+		return -1;
+	}
+
+	l = 0;
+	itn = pt->head;
+
+	while (itn != NULL && l < tomatch->len && l < MT_MAX_DEPTH) {
+		/* check validity */
+		if(_mt_char_table[(unsigned int)tomatch->s[l]]==255) {
+			LM_ERR("invalid char at %d in [%.*s]\n",
+					l, tomatch->len, tomatch->s);
+			return -1;
+		}
+		tvalues = itn[_mt_char_table[(unsigned int)tomatch->s[l]]].tvalues;
+		while (tvalues != NULL) {
+			node = add_mi_node_child(rpl, 0, "MT", 2, 0, 0);
+			if(node == NULL)
+				return -1;
+			if( add_mi_attr(node, MI_DUP_VALUE, "TNAME", 5,
+					pt->tname.s, pt->tname.len) == NULL)
+				return -1;
+			if (add_mi_attr(node, MI_DUP_VALUE, "TPREFIX", 7,
+						tomatch->s, l+1) == NULL)
+				return -1;
+			if (pt->type == MT_TREE_IVAL) {
+				attr = addf_mi_attr(node, MI_DUP_VALUE, "TVALUE", 6,
+						"%d", tvalues->tvalue.n);
+			} else {  /* pt->type == MT_TREE_SVAL */
+				attr = add_mi_attr(node, MI_DUP_VALUE, "TVALUE", 6,
+						tvalues->tvalue.s.s, tvalues->tvalue.s.len);
+			}
+			tvalues = tvalues->next;
+			if (attr == NULL)
+				return -1;
+		}
+
+		itn = itn[_mt_char_table[(unsigned int)tomatch->s[l]]].child;
+		l++;
+	}
+
+	if (node == NULL) return -1;
+
+	return 0;
+}
+
+int mt_mi_match_prefix(struct mi_node *rpl, m_tree_t *it,
+		str *tomatch, int mode)
+{
+	int l, len, n;
+	int i, j;
+	mt_node_t *itn;
+	is_t *tvalue;
+	mt_dw_t *dw;
+	int tprefix_len = 0;
+
+	struct mi_node *node;
+	struct mi_attr* attr= NULL;
+
+#define MT_MAX_DST_LIST	64
+	unsigned int tmp_list[2*(MT_MAX_DST_LIST+1)];
+
+	if(it==NULL || tomatch == NULL
+			|| tomatch->s == NULL)
+	{
+		LM_ERR("bad parameters\n");
+		return -1;
+	}
+
+	l = len = 0;
+	n = 0;
+	if ((it->type==MT_TREE_SVAL) || (it->type==MT_TREE_IVAL)) {
+		if (mode == 2)
+			return mt_mi_add_tvalues(rpl, it, tomatch);
+		tvalue = mt_get_tvalue(it, tomatch, &tprefix_len);
+		if (tvalue == NULL) {
+			LM_DBG("no match for: %.*s\n", tomatch->len, tomatch->s);
+			return -1;
+		}
+		if (tvalue) {
+			node = add_mi_node_child(rpl, 0, "MT", 2, 0, 0);
+			if(node == NULL)
+				return -1;
+			if( add_mi_attr(node, MI_DUP_VALUE, "TNAME", 5,
+					it->tname.s, it->tname.len) == NULL)
+				return -1;
+			if (add_mi_attr(node, MI_DUP_VALUE, "TPREFIX", 7,
+						tomatch->s, tprefix_len) == NULL)
+				return -1;
+			if (it->type==MT_TREE_SVAL) {
+				attr = add_mi_attr(node, MI_DUP_VALUE, "TVALUE", 6,
+										tvalue->s.s, tvalue->s.len);
+			} else {
+				attr = addf_mi_attr(node, MI_DUP_VALUE, "TVALUE", 6,
+										"%d", tvalue->n);
+			}
+			if (attr == NULL)
+				return -1;
+		}
+		return 0;
+	}
+
+	if(it->type!=MT_TREE_DW)
+		return -1; /* wrong tree type */
+
+	itn = it->head;
+	memset(tmp_list, 0, sizeof(unsigned int)*2*(MT_MAX_DST_LIST+1));
+
+	while(itn!=NULL && l < tomatch->len && l < MT_MAX_DEPTH)
+	{
+		/* check validity */
+		if(_mt_char_table[(unsigned int)tomatch->s[l]]==255)
+		{
+			LM_ERR("invalid char at %d in [%.*s]\n",
+					l, tomatch->len, tomatch->s);
+			return -1;
+		}
+
+		if(itn[_mt_char_table[(unsigned int)tomatch->s[l]]].tvalues!=NULL)
+		{
+			dw = (mt_dw_t*)itn[_mt_char_table[(unsigned int)tomatch->s[l]]].data;
+			while(dw) {
+				tmp_list[2*n]=dw->dstid;
+				tmp_list[2*n+1]=dw->weight;
+				n++;
+				if(n==MT_MAX_DST_LIST)
+					break;
+				dw = dw->next;
+			}
+			len = l+1;
+		}
+		if(n==MT_MAX_DST_LIST)
+			break;
+
+		itn = itn[_mt_char_table[(unsigned int)tomatch->s[l]]].child;
+		l++;
+	}
+
+	if(n==0)
+		return -1; /* no match */
+	/* invalidate duplicated dstid, keeping longest match */
+	for(i=(n-1); i>0; i--)
+	{
+		if (tmp_list[2*i]!=0)
+		{
+			for(j=0; j<i; j++)
+				if(tmp_list[2*i]==tmp_list[2*j])
+					tmp_list[2*j] = 0;
+		}
+	}
+	/* sort the table -- bubble sort -- reverse order */
+	for (i = (n - 1); i >= 0; i--)
+	{
+		for (j = 1; j <= i; j++)
+		{
+			if (tmp_list[2*(j-1)+1] < tmp_list[2*j+1])
+			{
+				tmp_list[2*MT_MAX_DST_LIST]   = tmp_list[2*(j-1)];
+				tmp_list[2*MT_MAX_DST_LIST+1] = tmp_list[2*(j-1)+1];
+				tmp_list[2*(j-1)]   = tmp_list[2*j];
+				tmp_list[2*(j-1)+1] = tmp_list[2*j+1];
+				tmp_list[2*j]   = tmp_list[2*MT_MAX_DST_LIST];
+				tmp_list[2*j+1] = tmp_list[2*MT_MAX_DST_LIST+1];
+			}
+		}
+	}
+
+	/* add as attributes */
+	for(i=0; i<n; i++)
+	{
+		if(tmp_list[2*i]!=0)
+		{
+			node = add_mi_node_child(rpl, 0, "MT", 2, 0, 0);
+			if(node == NULL)
+				return -1;
+			if( add_mi_attr(node, MI_DUP_VALUE, "TNAME", 5,
+					it->tname.s, it->tname.len) == NULL)
+				return -1;
+			if (add_mi_attr(node, MI_DUP_VALUE, "TPREFIX", 7,
+						tomatch->s, len) == NULL)
+				return -1;
+			if(addf_mi_attr(node, MI_DUP_VALUE, "WEIGHT", 6,
+					"%d", (int)tmp_list[2*i+1]) == NULL)
+				return -1;
+
+			if (addf_mi_attr(node, MI_DUP_VALUE, "DSTID", 5,
+					"%d", (int)tmp_list[2*i]) == NULL)
+				return -1;
+
+		}
+	}
+
+	return 0;
+}
+
+int mt_rpc_add_tvalues(rpc_t* rpc, void* ctx, m_tree_t *pt, str *tomatch)
+{
+	int l;
+	mt_node_t *itn;
+	mt_is_t *tvalues;
+	void *vstruct = NULL;
+	str prefix = *tomatch;
+
+	if (pt == NULL || tomatch == NULL || tomatch->s == NULL) {
+		LM_ERR("bad parameters\n");
+		return -1;
+	}
+
+	l = 0;
+	itn = pt->head;
+
+	while (itn != NULL && l < tomatch->len && l < MT_MAX_DEPTH) {
+		/* check validity */
+		if(_mt_char_table[(unsigned int)tomatch->s[l]]==255) {
+			LM_ERR("invalid char at %d in [%.*s]\n",
+					l, tomatch->len, tomatch->s);
+			return -1;
+		}
+		tvalues = itn[_mt_char_table[(unsigned int)tomatch->s[l]]].tvalues;
+		while (tvalues != NULL) {
+			prefix.len = l+1;
+			if (rpc->add(ctx, "{", &vstruct) < 0) {
+				rpc->fault(ctx, 500, "Internal error adding struct");
+				return -1;
+			}
+			if(rpc->struct_add(vstruct, "S", "PREFIX", &prefix) < 0) {
+				rpc->fault(ctx, 500, "Internal error adding prefix");
+				return -1;
+			}
+			if (pt->type == MT_TREE_IVAL) {
+				if(rpc->struct_add(vstruct, "d", "TVALUE", tvalues->tvalue.n) < 0 ) {
+					rpc->fault(ctx, 500, "Internal error adding tvalue");
+					return -1;
+				}
+			} else {  /* pt->type == MT_TREE_SVAL */
+				if(rpc->struct_add(vstruct, "S", "TVALUE", &tvalues->tvalue.s) < 0 ) {
+					rpc->fault(ctx, 500, "Internal error adding tvalue");
+					return -1;
+				}
+			}
+			tvalues = tvalues->next;
+		}
+
+		itn = itn[_mt_char_table[(unsigned int)tomatch->s[l]]].child;
+		l++;
+	}
+
+	if (vstruct == NULL) return -1;
+
+	return 0;
+}
+
+int mt_rpc_match_prefix(rpc_t* rpc, void* ctx, m_tree_t *it,
+		str *tomatch, int mode)
+{
+	int l, len, n;
+	int i, j;
+	mt_node_t *itn;
+	is_t *tvalue;
+	mt_dw_t *dw;
+	int tprefix_len = 0;
+	str prefix = *tomatch;
+	void *vstruct = NULL;
+
+#define MT_MAX_DST_LIST	64
+	unsigned int tmp_list[2*(MT_MAX_DST_LIST+1)];
+
+	if(it==NULL || tomatch == NULL
+			|| tomatch->s == NULL)
+	{
+		LM_ERR("bad parameters\n");
+		return -1;
+	}
+
+	if (rpc->add(ctx, "S", &it->tname) < 0) {
+		rpc->fault(ctx, 500, "Internal error adding tname");
+		return -1;
+	}
+
+	l = len = 0;
+	n = 0;
+	if ((it->type==MT_TREE_SVAL) || (it->type==MT_TREE_IVAL)) {
+		if (mode == 2)
+			return mt_rpc_add_tvalues(rpc, ctx, it, tomatch);
+		tvalue = mt_get_tvalue(it, tomatch, &tprefix_len);
+		if (tvalue == NULL) {
+			LM_DBG("no match for: %.*s\n", tomatch->len, tomatch->s);
+			return -1;
+		}
+		if (tvalue) {
+			prefix.len = tprefix_len;
+			if (rpc->add(ctx, "{", &vstruct) < 0) {
+				rpc->fault(ctx, 500, "Internal error adding struct");
+				return -1;
+			}
+			if (rpc->struct_add(vstruct, "S", "PREFIX", &prefix) < 0) {
+				rpc->fault(ctx, 500, "Internal error adding prefix");
+				return -1;
+			}
+			if (it->type==MT_TREE_SVAL) {
+				if(rpc->struct_add(vstruct, "S", "TVALUE", &tvalue->s) < 0 ) {
+					rpc->fault(ctx, 500, "Internal error adding tvalue");
+					return -1;
+				}
+			} else {
+				if(rpc->struct_add(vstruct, "d", "TVALUE", tvalue->n) < 0 ) {
+					rpc->fault(ctx, 500, "Internal error adding tvalue");
+					return -1;
+				}
+			}
+		}
+		return 0;
+	}
+
+	if(it->type!=MT_TREE_DW)
+		return -1; /* wrong tree type */
+
+	itn = it->head;
+	memset(tmp_list, 0, sizeof(unsigned int)*2*(MT_MAX_DST_LIST+1));
+
+	while(itn!=NULL && l < tomatch->len && l < MT_MAX_DEPTH)
+	{
+		/* check validity */
+		if(_mt_char_table[(unsigned int)tomatch->s[l]]==255)
+		{
+			LM_ERR("invalid char at %d in [%.*s]\n",
+					l, tomatch->len, tomatch->s);
+			return -1;
+		}
+
+		if(itn[_mt_char_table[(unsigned int)tomatch->s[l]]].tvalues!=NULL)
+		{
+			dw = (mt_dw_t*)itn[_mt_char_table[(unsigned int)tomatch->s[l]]].data;
+			while(dw) {
+				tmp_list[2*n]=dw->dstid;
+				tmp_list[2*n+1]=dw->weight;
+				n++;
+				if(n==MT_MAX_DST_LIST)
+					break;
+				dw = dw->next;
+			}
+			len = l+1;
+		}
+		if(n==MT_MAX_DST_LIST)
+			break;
+
+		itn = itn[_mt_char_table[(unsigned int)tomatch->s[l]]].child;
+		l++;
+	}
+
+	if(n==0)
+		return -1; /* no match */
+	/* invalidate duplicated dstid, keeping longest match */
+	for(i=(n-1); i>0; i--)
+	{
+		if (tmp_list[2*i]!=0)
+		{
+			for(j=0; j<i; j++)
+				if(tmp_list[2*i]==tmp_list[2*j])
+					tmp_list[2*j] = 0;
+		}
+	}
+	/* sort the table -- bubble sort -- reverse order */
+	for (i = (n - 1); i >= 0; i--)
+	{
+		for (j = 1; j <= i; j++)
+		{
+			if (tmp_list[2*(j-1)+1] < tmp_list[2*j+1])
+			{
+				tmp_list[2*MT_MAX_DST_LIST]   = tmp_list[2*(j-1)];
+				tmp_list[2*MT_MAX_DST_LIST+1] = tmp_list[2*(j-1)+1];
+				tmp_list[2*(j-1)]   = tmp_list[2*j];
+				tmp_list[2*(j-1)+1] = tmp_list[2*j+1];
+				tmp_list[2*j]   = tmp_list[2*MT_MAX_DST_LIST];
+				tmp_list[2*j+1] = tmp_list[2*MT_MAX_DST_LIST+1];
+			}
+		}
+	}
+
+	prefix.len = len;
+
+	/* add as attributes */
+	for(i=0; i<n; i++)
+	{
+		if(tmp_list[2*i]!=0)
+		{
+			if (rpc->add(ctx, "{", &vstruct) < 0) {
+				rpc->fault(ctx, 500, "Internal error adding struct");
+				return -1;
+			}
+			if (rpc->struct_add(vstruct, "S", "PREFIX", &prefix) < 0) {
+				rpc->fault(ctx, 500, "Internal error adding prefix");
+				return -1;
+			}
+			if(rpc->add(vstruct, "dd",
+					"WEIGHT", tmp_list[2*i+1],
+					"DSTID", tmp_list[2*i]) < 0 ) {
+				rpc->fault(ctx, 500, "Internal error adding weight/dstid");
+				return -1;
+			}
+		}
+	}
+
+	return 0;
+}

+ 7 - 1
modules/mtree/mtree.h

@@ -27,6 +27,8 @@
 
 #include "../../str.h"
 #include "../../parser/msg_parser.h"
+#include "../../lib/kmi/mi.h"
+#include "../../rpc.h"
 
 #define MT_TREE_SVAL	0	
 #define MT_TREE_DW	1
@@ -81,7 +83,7 @@ int mt_add_to_tree(m_tree_t *pt, str *tprefix, str *svalue);
 m_tree_t* mt_get_tree(str *tname);
 m_tree_t* mt_get_first_tree();
 
-is_t* mt_get_tvalue(m_tree_t *pt, str *tomatch);
+is_t* mt_get_tvalue(m_tree_t *pt, str *tomatch, int *len);
 int mt_match_prefix(struct sip_msg *msg, m_tree_t *pt,
 		    str *tomatch, int mode);
 
@@ -103,5 +105,9 @@ int mt_init_list_head(void);
 m_tree_t *mt_add_tree(m_tree_t **dpt, str *tname, str *dbtable,
 		      int type, int multi);
 
+int mt_mi_match_prefix(struct mi_node *rpl, m_tree_t *pt,
+		    str *tomatch, int mode);
+int mt_rpc_match_prefix(rpc_t* rpc, void* ctx, m_tree_t *pt,
+		    str *tomatch, int mode);
 #endif
 

+ 170 - 0
modules/mtree/mtree_mod.c

@@ -119,6 +119,7 @@ static int mt_match(struct sip_msg *msg, gparam_t *dm, gparam_t *var,
 static struct mi_root* mt_mi_reload(struct mi_root*, void* param);
 static struct mi_root* mt_mi_list(struct mi_root*, void* param);
 static struct mi_root* mt_mi_summary(struct mi_root*, void* param);
+static struct mi_root* mt_mi_match(struct mi_root*, void* param);
 
 static int mt_load_db(m_tree_t *pt);
 static int mt_load_db_trees();
@@ -153,6 +154,7 @@ static mi_export_t mi_cmds[] = {
 	{ "mt_reload",  mt_mi_reload,  0,  0,  mi_child_init },
 	{ "mt_list",    mt_mi_list,    0,  0,  0 },
 	{ "mt_summary", mt_mi_summary, 0,  0,  0 },
+	{ "mt_match", mt_mi_match, 0,  0,  0 },
 	{ 0, 0, 0, 0, 0}
 };
 
@@ -1116,9 +1118,77 @@ static const char* rpc_mtree_reload_doc[2] = {
 	0
 };
 
+void rpc_mtree_match(rpc_t* rpc, void* ctx)
+{
+	str tname = STR_NULL;
+	str tomatch = STR_NULL;
+	int mode = -1;
+
+	m_tree_t *tr;
+
+	if(!mt_defined_trees())
+	{
+		rpc->fault(ctx, 500, "Empty tree list.");
+		return;
+	}
+
+	if (rpc->scan(ctx, ".SSd", &tname, &tomatch, &mode) < 3) {
+		rpc->fault(ctx, 500, "Invalid Parameters");
+		return;
+	}
+
+	if (mode !=0 && mode != 2) {
+		rpc->fault(ctx, 500, "Invalid parameter 'mode'");
+		return;
+	}
+
+again:
+	lock_get( mt_lock );
+	if (mt_reload_flag) {
+		lock_release( mt_lock );
+		sleep_us(5);
+		goto again;
+	}
+	mt_tree_refcnt++;
+	lock_release( mt_lock );
+
+	tr = mt_get_tree(&tname);
+	if(tr==NULL)
+	{
+		/* no tree with such name*/
+		rpc->fault(ctx, 404, "Not found tree");
+		goto error;
+	}
+
+	if(mt_rpc_match_prefix(rpc, ctx, tr, &tomatch, mode)<0)
+	{
+		LM_DBG("no prefix found in [%.*s] for [%.*s]\n",
+				tname.len, tname.s,
+				tomatch.len, tomatch.s);
+		rpc->fault(ctx, 404, "Not found");
+	}
+
+error:
+	lock_get( mt_lock );
+	mt_tree_refcnt--;
+	lock_release( mt_lock );
+
+}
+
+static const char* rpc_mtree_match_doc[6] = {
+	"Match prefix value against mtree",
+	"uses three required parametes",
+	"tname - tree name",
+	"prefix - prefix for matching",
+	"mode - mode for matching (0 or 2)",
+	0
+};
+
+
 rpc_export_t mtree_rpc[] = {
 	{"mtree.summary", rpc_mtree_summary, rpc_mtree_summary_doc, 0},
 	{"mtree.reload", rpc_mtree_reload, rpc_mtree_reload_doc, 0},
+	{"mtree.match", rpc_mtree_match, rpc_mtree_match_doc, 0},
 	{0, 0, 0, 0}
 };
 
@@ -1131,3 +1201,103 @@ static int mtree_init_rpc(void)
 	}
 	return 0;
 }
+
+struct mi_root* mt_mi_match(struct mi_root* cmd_tree, void* param)
+{
+	m_tree_t *tr;
+	struct mi_root* rpl_tree = NULL;
+	struct mi_node* node = NULL;
+
+	str tname, prefix, mode_param;
+	str bad_tname_param = STR_STATIC_INIT("Bad tname parameter");
+	str bad_prefix_param = STR_STATIC_INIT("Bad prefix parameter");
+	str bad_mode_param = STR_STATIC_INIT("Bad mode parameter");
+	int mode;
+
+	if(!mt_defined_trees())
+	{
+		LM_ERR("empty tree list\n");
+		return init_mi_tree( 500, "No trees", 8);
+	}
+
+	/* read tree name */
+	node = cmd_tree->node.kids;
+	if(node != NULL)
+	{
+		tname = node->value;
+		if(tname.s == NULL || tname.len== 0)
+			return init_mi_tree( 400, bad_tname_param.s, bad_tname_param.len);
+	}
+	else
+	{
+		return init_mi_tree( 400, bad_tname_param.s, bad_tname_param.len);
+	}
+
+	/* read given prefix */
+	node = node->next;
+	if(node != NULL)
+	{
+		prefix = node->value;
+		if(prefix.s == NULL || prefix.len== 0)
+			return init_mi_tree( 400, bad_prefix_param.s, bad_prefix_param.len);
+	}
+	else
+	{
+		return init_mi_tree( 400, bad_prefix_param.s, bad_prefix_param.len);
+	}
+
+	/* read mode parameter (required) */
+	node = node->next;
+	if (node != NULL)
+	{
+		mode_param = node->value;
+		if (mode_param.s == NULL || mode_param.len == 0 ||
+				str2int(&mode_param, (unsigned int*)&mode))
+			mode = -1;
+
+		if (mode != 0 && mode != 2)
+			return init_mi_tree( 400, bad_mode_param.s, bad_mode_param.len);
+	}
+	else
+	{
+		return init_mi_tree( 400, bad_mode_param.s, bad_mode_param.len);
+	}
+
+again:
+	lock_get( mt_lock );
+	if (mt_reload_flag) {
+		lock_release( mt_lock );
+		sleep_us(5);
+		goto again;
+	}
+	mt_tree_refcnt++;
+	lock_release( mt_lock );
+
+	tr = mt_get_tree(&tname);
+	if(tr==NULL)
+	{
+		/* no tree with such name*/
+		rpl_tree = init_mi_tree( 404, "Not found tree", 14);
+		goto error;
+	}
+
+	rpl_tree = init_mi_tree( 200, "OK", 2);
+	if (rpl_tree == NULL)
+		goto error;
+
+	if(mt_mi_match_prefix(&rpl_tree->node, tr, &prefix, mode)<0)
+	{
+		LM_DBG("no prefix found in [%.*s] for [%.*s]\n",
+				tname.len, tname.s,
+				prefix.len, prefix.s);
+		free_mi_tree(rpl_tree);
+		rpl_tree = init_mi_tree( 404, "Not found tvalue", 16);
+	}
+
+error:
+	lock_get( mt_lock );
+	mt_tree_refcnt--;
+	lock_release( mt_lock );
+
+	return rpl_tree;
+}