]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
DEBUG: tools: provide a tree dump function for ebmbtrees as well
authorWilly Tarreau <w@1wt.eu>
Mon, 1 Aug 2022 09:55:57 +0000 (11:55 +0200)
committerWilly Tarreau <w@1wt.eu>
Mon, 1 Aug 2022 09:59:15 +0000 (11:59 +0200)
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

include/haproxy/tools.h
src/tools.c

index 3059fa847aae9136746f27d0d66fa93baf5f0abb..abbca3f4d136d979e4cc2c1d7032975f3528e840 100644 (file)
@@ -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
index 36db6a48a884d2ebb293bbdb189c3105bdd1a673..2311f725a65acb55665e4d92f235733b39614470 100644 (file)
@@ -49,6 +49,7 @@ extern void *__elf_aux_vector;
 
 #include <import/eb32sctree.h>
 #include <import/eb32tree.h>
+#include <import/ebmbtree.h>
 
 #include <haproxy/api.h>
 #include <haproxy/applet.h>
@@ -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 <file> in DOT format for debugging purposes. Will
+ * optionally highlight node <subj> if found, depending on operation <op> :
+ *    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