MEDIUM: pattern: create pattern expression

This new structure contains the data needed for pattern matching. It's
the first step to the complete independance of the pattern matching.
This commit is contained in:
Thierry FOURNIER 2013-11-28 11:41:23 +01:00 committed by Willy Tarreau
parent ed66c297c2
commit d163e1ce30
5 changed files with 63 additions and 44 deletions

View File

@ -35,14 +35,14 @@
* fails, with <err> message filled. It returns -2 in "out of memory"
* error case.
*/
int acl_register_pattern(struct acl_expr *expr, char *text, struct sample_storage *smp, struct acl_pattern **pattern, int patflags, char **err);
int acl_register_pattern(struct pattern_expr *expr, char *text, struct sample_storage *smp, struct acl_pattern **pattern, int patflags, char **err);
/* This function executes a pattern match on a sample. It applies pattern <expr>
* to sample <smp>. If <sample> is not NULL, a pointer to an optional sample
* associated to the matching patterned will be put there. The function returns
* ACL_PAT_FAIL, ACL_PAT_MISS or ACL_PAT_PASS.
*/
inline int acl_exec_match(struct acl_expr *expr, struct sample *smp, struct sample_storage **sample);
inline int acl_exec_match(struct pattern_expr *expr, struct sample *smp, struct sample_storage **sample);
/*
*
@ -128,9 +128,9 @@ int acl_match_ip(struct sample *smp, struct acl_pattern *pattern);
*/
int acl_match_reg(struct sample *smp, struct acl_pattern *pattern);
int acl_read_patterns_from_file(struct acl_expr *expr, const char *filename, int patflags, char **err);
int acl_read_patterns_from_file(struct pattern_expr *expr, const char *filename, int patflags, char **err);
void free_pattern(struct acl_pattern *pat);
void free_pattern_list(struct list *head);
void free_pattern_tree(struct eb_root *root);
void prune_pattern_expr(struct pattern_expr *expr);
void init_pattern_expr(struct pattern_expr *expr);
#endif

View File

@ -105,17 +105,13 @@ struct acl_kw_list {
/*
* Description of an ACL expression.
* The expression is part of a list. It contains pointers to the keyword, the
* parse and match functions which default to the keyword's, the sample fetch
* descriptor which also defaults to the keyword's, and a list or tree of
* patterns to test against. The structure is organized so that the hot parts
* are grouped together in order to optimize caching.
* sample fetch descriptor which defaults to the keyword's, and the associated
* pattern matching. The structure is organized so that the hot parts are
* grouped together in order to optimize caching.
*/
struct acl_expr {
int (*parse)(const char **text, struct acl_pattern *pattern, struct sample_storage *smp, int *opaque, char **err);
int (*match)(struct sample *smp, struct acl_pattern *pattern);
struct sample_expr *smp; /* the sample expression we depend on */
struct list patterns; /* list of acl_patterns */
struct eb_root pattern_tree; /* may be used for lookup in large datasets */
struct pattern_expr pat; /* the pattern matching expression */
struct list list; /* chaining */
const char *kw; /* points to the ACL kw's name or fetch's name (must not free) */
};

View File

@ -121,6 +121,18 @@ struct acl_pattern {
};
/* Description of a pattern expression.
* It contains pointers to the parse and match functions, and a list or tree of
* patterns to test against. The structure is organized so that the hot parts
* are grouped together in order to optimize caching.
*/
struct pattern_expr {
int (*parse)(const char **text, struct acl_pattern *pattern, struct sample_storage *smp, int *opaque, char **err);
int (*match)(struct sample *smp, struct acl_pattern *pattern);
struct list patterns; /* list of acl_patterns */
struct eb_root pattern_tree; /* may be used for lookup in large datasets */
};
extern char *acl_match_names[ACL_MATCH_NUM];
extern int (*acl_parse_fcts[ACL_MATCH_NUM])(const char **, struct acl_pattern *, struct sample_storage *, int *, char **);
extern int (*acl_match_fcts[ACL_MATCH_NUM])(struct sample *, struct acl_pattern *);

View File

@ -107,9 +107,7 @@ static struct acl_expr *prune_acl_expr(struct acl_expr *expr)
{
struct arg *arg;
free_pattern_list(&expr->patterns);
free_pattern_tree(&expr->pattern_tree);
LIST_INIT(&expr->patterns);
prune_pattern_expr(&expr->pat);
for (arg = expr->smp->arg_p; arg; arg++) {
if (arg->type == ARGT_STOP)
@ -171,30 +169,30 @@ struct acl_expr *parse_acl_expr(const char **args, char **err, struct arg_list *
goto out_return;
}
init_pattern_expr(&expr->pat);
expr->kw = aclkw ? aclkw->kw : smp->fetch->kw;
LIST_INIT(&expr->patterns);
expr->pattern_tree = EB_ROOT_UNIQUE;
expr->parse = aclkw ? aclkw->parse : NULL;
expr->match = aclkw ? aclkw->match : NULL;
expr->pat.parse = aclkw ? aclkw->parse : NULL;
expr->pat.match = aclkw ? aclkw->match : NULL;
expr->smp = aclkw ? NULL : smp;
if (!expr->parse) {
if (!expr->pat.parse) {
/* some types can be automatically converted */
switch (expr->smp ? expr->smp->fetch->out_type : aclkw->smp->out_type) {
case SMP_T_BOOL:
expr->parse = acl_parse_fcts[ACL_MATCH_BOOL];
expr->match = acl_match_fcts[ACL_MATCH_BOOL];
expr->pat.parse = acl_parse_fcts[ACL_MATCH_BOOL];
expr->pat.match = acl_match_fcts[ACL_MATCH_BOOL];
break;
case SMP_T_SINT:
case SMP_T_UINT:
expr->parse = acl_parse_fcts[ACL_MATCH_INT];
expr->match = acl_match_fcts[ACL_MATCH_INT];
expr->pat.parse = acl_parse_fcts[ACL_MATCH_INT];
expr->pat.match = acl_match_fcts[ACL_MATCH_INT];
break;
case SMP_T_IPV4:
case SMP_T_IPV6:
expr->parse = acl_parse_fcts[ACL_MATCH_IP];
expr->match = acl_match_fcts[ACL_MATCH_IP];
expr->pat.parse = acl_parse_fcts[ACL_MATCH_IP];
expr->pat.match = acl_match_fcts[ACL_MATCH_IP];
break;
}
}
@ -430,7 +428,7 @@ struct acl_expr *parse_acl_expr(const char **args, char **err, struct arg_list *
/* Additional check to protect against common mistakes */
cur_type = smp_expr_output_type(expr->smp);
if (expr->parse && cur_type != SMP_T_BOOL && !*args[1]) {
if (expr->pat.parse && cur_type != SMP_T_BOOL && !*args[1]) {
Warning("parsing acl keyword '%s' :\n"
" no pattern to match against were provided, so this ACL will never match.\n"
" If this is what you intended, please add '--' to get rid of this warning.\n"
@ -453,19 +451,19 @@ struct acl_expr *parse_acl_expr(const char **args, char **err, struct arg_list *
if ((*args)[1] == 'i')
patflags |= ACL_PAT_F_IGNORE_CASE;
else if ((*args)[1] == 'f') {
if (!expr->parse) {
if (!expr->pat.parse) {
memprintf(err, "matching method must be specified first (using '-m') when using a sample fetch of this type ('%s')", expr->kw);
goto out_free_expr;
}
if (!acl_read_patterns_from_file(expr, args[1], patflags | ACL_PAT_F_FROM_FILE, err))
if (!acl_read_patterns_from_file(&expr->pat, args[1], patflags | ACL_PAT_F_FROM_FILE, err))
goto out_free_expr;
args++;
}
else if ((*args)[1] == 'm') {
int idx;
if (!LIST_ISEMPTY(&expr->patterns) || !eb_is_empty(&expr->pattern_tree)) {
if (!LIST_ISEMPTY(&expr->pat.patterns) || !eb_is_empty(&expr->pat.pattern_tree)) {
memprintf(err, "'-m' must only be specified before patterns and files in parsing ACL expression");
goto out_free_expr;
}
@ -492,8 +490,8 @@ struct acl_expr *parse_acl_expr(const char **args, char **err, struct arg_list *
cur_type == SMP_T_BIN ||
cur_type == SMP_T_CSTR ||
cur_type == SMP_T_CBIN))) {
expr->parse = acl_parse_fcts[idx];
expr->match = acl_match_fcts[idx];
expr->pat.parse = acl_parse_fcts[idx];
expr->pat.match = acl_match_fcts[idx];
}
else {
memprintf(err, "matching method '%s' cannot be used with fetch keyword '%s'", args[1], expr->kw);
@ -510,7 +508,7 @@ struct acl_expr *parse_acl_expr(const char **args, char **err, struct arg_list *
args++;
}
if (!expr->parse) {
if (!expr->pat.parse) {
memprintf(err, "matching method must be specified first (using '-m') when using a sample fetch of this type ('%s')", expr->kw);
goto out_free_expr;
}
@ -527,11 +525,11 @@ struct acl_expr *parse_acl_expr(const char **args, char **err, struct arg_list *
pattern->flags = patflags;
pattern->type = SMP_TYPES; /* unspecified type */
ret = expr->parse(args, pattern, NULL, &opaque, err);
ret = expr->pat.parse(args, pattern, NULL, &opaque, err);
if (!ret)
goto out_free_pattern;
LIST_ADDQ(&expr->patterns, &pattern->list);
LIST_ADDQ(&expr->pat.patterns, &pattern->list);
args += ret;
}
@ -1012,7 +1010,7 @@ int acl_exec_cond(struct acl_cond *cond, struct proxy *px, struct session *l4, v
continue;
}
acl_res |= acl_exec_match(expr, &smp, NULL);
acl_res |= acl_exec_match(&expr->pat, &smp, NULL);
/*
* OK now acl_res holds the result of this expression
* as one of ACL_PAT_FAIL, ACL_PAT_MISS or ACL_PAT_PASS.
@ -1136,14 +1134,14 @@ int acl_find_targets(struct proxy *p)
continue;
}
if (LIST_ISEMPTY(&expr->patterns)) {
if (LIST_ISEMPTY(&expr->pat.patterns)) {
Alert("proxy %s: acl %s %s(): no groups specified.\n",
p->id, acl->name, expr->kw);
cfgerr++;
continue;
}
list_for_each_entry(pattern, &expr->patterns, list) {
list_for_each_entry(pattern, &expr->pat.patterns, list) {
/* this keyword only has one argument */
pattern->val.group_mask = auth_resolve_groups(expr->smp->arg_p->data.usr, pattern->ptr.str);

View File

@ -117,7 +117,7 @@ int acl_match_bin(struct sample *smp, struct acl_pattern *pattern)
/* Lookup a string in the expression's pattern tree. The node is returned if it
* exists, otherwise NULL.
*/
static void *acl_lookup_str(struct sample *smp, struct acl_expr *expr)
static void *acl_lookup_str(struct sample *smp, struct pattern_expr *expr)
{
/* data are stored in a tree */
struct ebmb_node *node;
@ -389,7 +389,7 @@ int acl_match_ip(struct sample *smp, struct acl_pattern *pattern)
/* Lookup an IPv4 address in the expression's pattern tree using the longest
* match method. The node is returned if it exists, otherwise NULL.
*/
static void *acl_lookup_ip(struct sample *smp, struct acl_expr *expr)
static void *acl_lookup_ip(struct sample *smp, struct pattern_expr *expr)
{
struct in_addr *s;
@ -807,11 +807,24 @@ void free_pattern_tree(struct eb_root *root)
}
}
void prune_pattern_expr(struct pattern_expr *expr)
{
free_pattern_list(&expr->patterns);
free_pattern_tree(&expr->pattern_tree);
LIST_INIT(&expr->patterns);
}
void init_pattern_expr(struct pattern_expr *expr)
{
LIST_INIT(&expr->patterns);
expr->pattern_tree = EB_ROOT_UNIQUE;
}
/* return 1 if the process is ok
* return -1 if the parser fail. The err message is filled.
* return -2 if out of memory
*/
int acl_register_pattern(struct acl_expr *expr, char *text,
int acl_register_pattern(struct pattern_expr *expr, char *text,
struct sample_storage *smp,
struct acl_pattern **pattern,
int patflags, char **err)
@ -856,7 +869,7 @@ int acl_register_pattern(struct acl_expr *expr, char *text,
/* Reads patterns from a file. If <err_msg> is non-NULL, an error message will
* be returned there on errors and the caller will have to free it.
*/
int acl_read_patterns_from_file(struct acl_expr *expr,
int acl_read_patterns_from_file(struct pattern_expr *expr,
const char *filename, int patflags,
char **err)
{
@ -926,7 +939,7 @@ int acl_read_patterns_from_file(struct acl_expr *expr,
* is not NULL. The function return ACL_PAT_FAIL, ACL_PAT_MISS or
* ACL_PAT_PASS
*/
inline int acl_exec_match(struct acl_expr *expr, struct sample *smp,
inline int acl_exec_match(struct pattern_expr *expr, struct sample *smp,
struct sample_storage **sample)
{
int acl_res = ACL_PAT_FAIL;