From: Willy Tarreau Date: Mon, 1 Aug 2022 09:55:57 +0000 (+0200) Subject: DEBUG: tools: provide a tree dump function for ebmbtrees as well X-Git-Tag: v2.7-dev3~46 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0dc9e6dca2b32a288dcd272b4606a01fa712010c;p=thirdparty%2Fhaproxy.git DEBUG: tools: provide a tree dump function for ebmbtrees as well It's convenient for debugging IP trees. However we're not dumping the full keys, for the sake of simplicity, only the 4 first bytes are dumped as a u32 hex value. In practice this is sufficient for debugging. As a reminder since it seems difficult to recover the command each time it's needed, the output is converted to an image using dot from Graphviz: dot -o a.png -Tpng dump.txt --- diff --git a/include/haproxy/tools.h b/include/haproxy/tools.h index 3059fa847a..abbca3f4d1 100644 --- a/include/haproxy/tools.h +++ b/include/haproxy/tools.h @@ -616,6 +616,10 @@ unsigned int get_next_id(struct eb_root *root, unsigned int key); void eb32sc_to_file(FILE *file, struct eb_root *root, const struct eb32sc_node *subj, int op, const char *desc); +/* same but for ebmb */ +void ebmb_to_file(FILE *file, struct eb_root *root, const struct ebmb_node *subj, + int op, const char *desc); + /* This function compares a sample word possibly followed by blanks to another * clean word. The compare is case-insensitive. 1 is returned if both are equal, * otherwise zero. This intends to be used when checking HTTP headers for some diff --git a/src/tools.c b/src/tools.c index 36db6a48a8..2311f725a6 100644 --- a/src/tools.c +++ b/src/tools.c @@ -49,6 +49,7 @@ extern void *__elf_aux_vector; #include #include +#include #include #include @@ -2762,6 +2763,76 @@ void eb32sc_to_file(FILE *file, struct eb_root *root, const struct eb32sc_node * fprintf(file, "}\n"); } +/* dump the full tree to in DOT format for debugging purposes. Will + * optionally highlight node if found, depending on operation : + * 0 : nothing + * >0 : insertion, node/leaf are surrounded in red + * <0 : removal, node/leaf are dashed with no background + * Will optionally add "desc" as a label on the graph if set and non-null. The + * key is printed as a u32 hex value. A full-sized hex dump would be better but + * is left to be implemented. + */ +void ebmb_to_file(FILE *file, struct eb_root *root, const struct ebmb_node *subj, int op, const char *desc) +{ + struct ebmb_node *node; + + fprintf(file, "digraph ebtree {\n"); + + if (desc && *desc) { + fprintf(file, + " fontname=\"fixed\";\n" + " fontsize=8;\n" + " label=\"%s\";\n", desc); + } + + fprintf(file, + " node [fontname=\"fixed\" fontsize=8 shape=\"box\" style=\"filled\" color=\"black\" fillcolor=\"white\"];\n" + " edge [fontname=\"fixed\" fontsize=8 style=\"solid\" color=\"magenta\" dir=\"forward\"];\n" + " \"%lx_n\" [label=\"root\\n%lx\"]\n", (long)eb_root_to_node(root), (long)root + ); + + fprintf(file, " \"%lx_n\" -> \"%lx_%c\" [taillabel=\"L\"];\n", + (long)eb_root_to_node(root), + (long)eb_root_to_node(eb_clrtag(root->b[0])), + eb_gettag(root->b[0]) == EB_LEAF ? 'l' : 'n'); + + node = ebmb_first(root); + while (node) { + if (node->node.node_p) { + /* node part is used */ + fprintf(file, " \"%lx_n\" [label=\"%lx\\nkey=%#x\\nbit=%d\" fillcolor=\"lightskyblue1\" %s];\n", + (long)node, (long)node, read_u32(node->key), node->node.bit, + (node == subj) ? (op < 0 ? "color=\"red\" style=\"dashed\"" : op > 0 ? "color=\"red\"" : "") : ""); + + fprintf(file, " \"%lx_n\" -> \"%lx_n\" [taillabel=\"%c\"];\n", + (long)node, + (long)eb_root_to_node(eb_clrtag(node->node.node_p)), + eb_gettag(node->node.node_p) ? 'R' : 'L'); + + fprintf(file, " \"%lx_n\" -> \"%lx_%c\" [taillabel=\"L\"];\n", + (long)node, + (long)eb_root_to_node(eb_clrtag(node->node.branches.b[0])), + eb_gettag(node->node.branches.b[0]) == EB_LEAF ? 'l' : 'n'); + + fprintf(file, " \"%lx_n\" -> \"%lx_%c\" [taillabel=\"R\"];\n", + (long)node, + (long)eb_root_to_node(eb_clrtag(node->node.branches.b[1])), + eb_gettag(node->node.branches.b[1]) == EB_LEAF ? 'l' : 'n'); + } + + fprintf(file, " \"%lx_l\" [label=\"%lx\\nkey=%#x\\npfx=%u\" fillcolor=\"yellow\" %s];\n", + (long)node, (long)node, read_u32(node->key), node->node.pfx, + (node == subj) ? (op < 0 ? "color=\"red\" style=\"dashed\"" : op > 0 ? "color=\"red\"" : "") : ""); + + fprintf(file, " \"%lx_l\" -> \"%lx_n\" [taillabel=\"%c\"];\n", + (long)node, + (long)eb_root_to_node(eb_clrtag(node->node.leaf_p)), + eb_gettag(node->node.leaf_p) ? 'R' : 'L'); + node = ebmb_next(node); + } + fprintf(file, "}\n"); +} + /* This function compares a sample word possibly followed by blanks to another * clean word. The compare is case-insensitive. 1 is returned if both are equal, * otherwise zero. This intends to be used when checking HTTP headers for some