MINOR: pattern: add function to lookup a specific entry in pattern list
This is used to dynamically delete or update map entry.
diff --git a/include/proto/pattern.h b/include/proto/pattern.h
index 8c9c1c7..080b062 100644
--- a/include/proto/pattern.h
+++ b/include/proto/pattern.h
@@ -151,5 +151,7 @@
void pattern_free(struct pattern *pat);
void pattern_prune_expr(struct pattern_expr *expr);
void pattern_init_expr(struct pattern_expr *expr);
+int pattern_lookup(const char *args, struct pattern_expr *expr, struct pattern **pat_elt, struct pat_idx_elt **idx_elt, char **err);
+
#endif
diff --git a/src/pattern.c b/src/pattern.c
index c9e8978..99d6e8b 100644
--- a/src/pattern.c
+++ b/src/pattern.c
@@ -1101,3 +1101,166 @@
return pat_res;
}
+/* This function browse the pattern expr <expr> to lookup the key <key>. On
+ * error it returns 0. On success, it returns 1 and fills either <pat_elt>
+ * or <idx_elt> with the respectively matched pointers, and the other one with
+ * NULL. Pointers are not set if they're passed as NULL.
+ */
+int pattern_lookup(const char *key, struct pattern_expr *expr,
+ struct pattern **pat_elt, struct pat_idx_elt **idx_elt, char **err)
+{
+ struct pattern pattern;
+ struct pattern *pat;
+ struct ebmb_node *node;
+ struct pat_idx_elt *elt;
+ const char *args[2];
+ int opaque = 0;
+ unsigned int mask;
+
+ /* no real pattern */
+ if (!expr->match || expr->match == pat_match_nothing)
+ return 0;
+
+ /* build lookup pattern */
+ args[0] = key;
+ args[1] = "";
+ if (!expr->parse(args, &pattern, PAT_U_LOOKUP, &opaque, NULL))
+ return 0;
+
+ pat = NULL;
+ elt = NULL;
+ /* The current pattern is a tree, try to look up */
+ if (!eb_is_empty(&expr->pattern_tree)) {
+ /* IPv6 is not indexed */
+ if (pattern.type == SMP_T_IPV6)
+ goto browse_list;
+
+ /* Check the pattern type */
+ if (pattern.type != SMP_T_STR &&
+ pattern.type != SMP_T_CSTR &&
+ pattern.type != SMP_T_IPV4) {
+ memprintf(err, "Unexpected pattern type.");
+ return 0;
+ }
+
+ /* Convert mask. If the mask is not contiguous, ignore the lookup
+ * in the tree, and browse the list.
+ */
+ if (expr->match == pat_match_ip) {
+ mask = ntohl(pattern.val.ipv4.mask.s_addr);
+ if (mask + (mask & -mask) != 0)
+ goto browse_list;
+ mask = mask ? 33 - flsnz(mask & -mask) : 0; /* equals cidr value */
+ }
+
+ /* browse each node of the tree, and check string */
+ if (expr->match == pat_match_str) {
+ for (node = ebmb_first(&expr->pattern_tree);
+ node;
+ node = ebmb_next(node)) {
+ elt = container_of(node, struct pat_idx_elt, node);
+ if (strcmp(pattern.ptr.str, (char *)elt->node.key) == 0)
+ goto found;
+ }
+ }
+ else if (expr->match == pat_match_ip) {
+ for (node = ebmb_first(&expr->pattern_tree);
+ node;
+ node = ebmb_next(node)) {
+ elt = container_of(node, struct pat_idx_elt, node);
+ if (elt->node.node.pfx == mask &&
+ memcmp(&pattern.val.ipv4.addr.s_addr, elt->node.key, 4) == 0)
+ goto found;
+ }
+ }
+ }
+
+browse_list:
+ if (expr->parse == pat_parse_int ||
+ expr->parse == pat_parse_len) {
+ list_for_each_entry(pat, &expr->patterns, list) {
+ if (pat->flags & PAT_F_TREE)
+ continue;
+ if (pattern.val.range.min_set != pat->val.range.min_set)
+ continue;
+ if (pattern.val.range.max_set != pat->val.range.max_set)
+ continue;
+ if (pattern.val.range.min_set &&
+ pattern.val.range.min != pat->val.range.min)
+ continue;
+ if (pattern.val.range.max_set &&
+ pattern.val.range.max != pat->val.range.max)
+ continue;
+ goto found;
+ }
+ }
+ else if (expr->parse == pat_parse_ip) {
+ list_for_each_entry(pat, &expr->patterns, list) {
+ if (pat->flags & PAT_F_TREE)
+ continue;
+ if (pattern.type != pat->type)
+ continue;
+ if (pattern.type == SMP_T_IPV4 &&
+ memcmp(&pattern.val.ipv4.addr, &pat->val.ipv4.addr, sizeof(pat->val.ipv4.addr)) != 0)
+ continue;
+ if (pattern.type == SMP_T_IPV4 &&
+ memcmp(&pattern.val.ipv4.mask, &pat->val.ipv4.mask, sizeof(pat->val.ipv4.addr)) != 0)
+ continue;
+ if (pattern.type == SMP_T_IPV6 &&
+ memcmp(&pattern.val.ipv6.addr, &pat->val.ipv6.addr, sizeof(pat->val.ipv6.addr)) != 0)
+ continue;
+ if (pattern.type == SMP_T_IPV6 &&
+ pattern.val.ipv6.mask != pat->val.ipv6.mask)
+ continue;
+ goto found;
+ }
+ }
+ else if (expr->parse == pat_parse_str) {
+ list_for_each_entry(pat, &expr->patterns, list) {
+ if (pat->flags & PAT_F_TREE)
+ continue;
+ if (pattern.len != pat->len)
+ continue;
+ if ((pat->flags & PAT_F_IGNORE_CASE) &&
+ strncasecmp(pattern.ptr.str, pat->ptr.str, pat->len) != 0)
+ continue;
+ if (strncmp(pattern.ptr.str, pat->ptr.str, pat->len) != 0)
+ continue;
+ goto found;
+ }
+ }
+ else if (expr->parse == pat_parse_bin) {
+ list_for_each_entry(pat, &expr->patterns, list) {
+ if (pat->flags & PAT_F_TREE)
+ continue;
+ if (pattern.len != pat->len)
+ continue;
+ if (memcmp(pattern.ptr.ptr, pat->ptr.ptr, pat->len) != 0)
+ continue;
+ goto found;
+ }
+ }
+ else if (expr->parse == pat_parse_reg) {
+ list_for_each_entry(pat, &expr->patterns, list) {
+ if (pat->flags & PAT_F_TREE)
+ continue;
+ if ((pat->flags & PAT_F_IGNORE_CASE) &&
+ strcasecmp(pattern.ptr.reg->regstr, pat->ptr.reg->regstr) != 0)
+ continue;
+ if (strcmp(pattern.ptr.reg->regstr, pat->ptr.reg->regstr) != 0)
+ continue;
+ goto found;
+ }
+ }
+
+ /* if we get there, we didn't find the pattern */
+ return 0;
+found:
+ if (idx_elt)
+ *idx_elt = elt;
+
+ if (pat_elt)
+ *pat_elt = pat;
+
+ return 1;
+}