mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2024-12-11 22:15:14 +00:00
MINOR: pattern/ip: simplify pat_match_ip() function
pat_match_ip() has been updated several times over the last decade to introduce new features, but it was never cleaned up. The result is that the function is pretty hard to read, and there are multiple duplicated code blocks so it becomes error-prone to maintain it, plus it bloats the haproxy binary for nothing. In this patch, we move the tree search (ip4 / ip6) logic into 2 dedicated helper functions. This allows us to refactor pat_match_ip() without touching to the original behavior.
This commit is contained in:
parent
acb7d8a89c
commit
0189a4679e
194
src/pattern.c
194
src/pattern.c
@ -964,138 +964,128 @@ struct pattern *pat_match_len(struct sample *smp, struct pattern_expr *expr, int
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct pattern *pat_match_ip(struct sample *smp, struct pattern_expr *expr, int fill)
|
/* Performs ipv4 key lookup in <expr> ipv4 tree
|
||||||
|
* Returns NULL on failure
|
||||||
|
*/
|
||||||
|
static struct pattern *_pat_match_tree_ipv4(struct in_addr *key, struct pattern_expr *expr, int fill)
|
||||||
{
|
{
|
||||||
struct in_addr v4; /* in network byte order */
|
|
||||||
struct in6_addr tmp6;
|
|
||||||
struct in_addr *s;
|
|
||||||
struct ebmb_node *node;
|
struct ebmb_node *node;
|
||||||
struct pattern_tree *elt;
|
struct pattern_tree *elt;
|
||||||
|
|
||||||
|
/* Lookup an IPv4 address in the expression's pattern tree using
|
||||||
|
* the longest match method.
|
||||||
|
*/
|
||||||
|
node = ebmb_lookup_longest(&expr->pattern_tree, key);
|
||||||
|
while (node) {
|
||||||
|
elt = ebmb_entry(node, struct pattern_tree, node);
|
||||||
|
if (elt->ref->gen_id != expr->ref->curr_gen) {
|
||||||
|
node = ebmb_lookup_shorter(node);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (fill) {
|
||||||
|
static_pattern.data = elt->data;
|
||||||
|
static_pattern.ref = elt->ref;
|
||||||
|
static_pattern.sflags = PAT_SF_TREE;
|
||||||
|
static_pattern.type = SMP_T_IPV4;
|
||||||
|
static_pattern.val.ipv4.addr.s_addr = read_u32(elt->node.key);
|
||||||
|
if (!cidr2dotted(elt->node.node.pfx, &static_pattern.val.ipv4.mask))
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return &static_pattern;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Performs ipv6 key lookup in <expr> ipv6 tree
|
||||||
|
* Returns NULL on failure
|
||||||
|
*/
|
||||||
|
static struct pattern *_pat_match_tree_ipv6(struct in6_addr *key, struct pattern_expr *expr, int fill)
|
||||||
|
{
|
||||||
|
struct ebmb_node *node;
|
||||||
|
struct pattern_tree *elt;
|
||||||
|
|
||||||
|
/* Lookup an IPv6 address in the expression's pattern tree using
|
||||||
|
* the longest match method.
|
||||||
|
*/
|
||||||
|
node = ebmb_lookup_longest(&expr->pattern_tree_2, key);
|
||||||
|
while (node) {
|
||||||
|
elt = ebmb_entry(node, struct pattern_tree, node);
|
||||||
|
if (elt->ref->gen_id != expr->ref->curr_gen) {
|
||||||
|
node = ebmb_lookup_shorter(node);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (fill) {
|
||||||
|
static_pattern.data = elt->data;
|
||||||
|
static_pattern.ref = elt->ref;
|
||||||
|
static_pattern.sflags = PAT_SF_TREE;
|
||||||
|
static_pattern.type = SMP_T_IPV6;
|
||||||
|
memcpy(&static_pattern.val.ipv6.addr, elt->node.key, 16);
|
||||||
|
static_pattern.val.ipv6.mask = elt->node.node.pfx;
|
||||||
|
}
|
||||||
|
return &static_pattern;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct pattern *pat_match_ip(struct sample *smp, struct pattern_expr *expr, int fill)
|
||||||
|
{
|
||||||
|
struct in_addr v4;
|
||||||
|
struct in6_addr v6;
|
||||||
struct pattern_list *lst;
|
struct pattern_list *lst;
|
||||||
struct pattern *pattern;
|
struct pattern *pattern;
|
||||||
|
|
||||||
/* The input sample is IPv4. Try to match in the trees. */
|
/* The input sample is IPv4. Try to match in the trees. */
|
||||||
if (smp->data.type == SMP_T_IPV4) {
|
if (smp->data.type == SMP_T_IPV4) {
|
||||||
/* Lookup an IPv4 address in the expression's pattern tree using
|
pattern = _pat_match_tree_ipv4(&smp->data.u.ipv4, expr, fill);
|
||||||
* the longest match method.
|
if (pattern)
|
||||||
*/
|
return pattern;
|
||||||
s = &smp->data.u.ipv4;
|
|
||||||
node = ebmb_lookup_longest(&expr->pattern_tree, &s->s_addr);
|
|
||||||
while (node) {
|
|
||||||
elt = ebmb_entry(node, struct pattern_tree, node);
|
|
||||||
if (elt->ref->gen_id != expr->ref->curr_gen) {
|
|
||||||
node = ebmb_lookup_shorter(node);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (fill) {
|
|
||||||
static_pattern.data = elt->data;
|
|
||||||
static_pattern.ref = elt->ref;
|
|
||||||
static_pattern.sflags = PAT_SF_TREE;
|
|
||||||
static_pattern.type = SMP_T_IPV4;
|
|
||||||
static_pattern.val.ipv4.addr.s_addr = read_u32(elt->node.key);
|
|
||||||
if (!cidr2dotted(elt->node.node.pfx, &static_pattern.val.ipv4.mask))
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
return &static_pattern;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The IPv4 sample don't match the IPv4 tree. Convert the IPv4
|
/* The IPv4 sample don't match the IPv4 tree. Convert the IPv4
|
||||||
* sample address to IPv6 and try to lookup in the IPv6 tree.
|
* sample address to IPv6 and try to lookup in the IPv6 tree.
|
||||||
*/
|
*/
|
||||||
v4tov6(&tmp6, &smp->data.u.ipv4);
|
v4tov6(&v6, &smp->data.u.ipv4);
|
||||||
node = ebmb_lookup_longest(&expr->pattern_tree_2, &tmp6);
|
pattern = _pat_match_tree_ipv6(&v6, expr, fill);
|
||||||
while (node) {
|
if (pattern)
|
||||||
elt = ebmb_entry(node, struct pattern_tree, node);
|
return pattern;
|
||||||
if (elt->ref->gen_id != expr->ref->curr_gen) {
|
/* eligible for list lookup using IPv4 address */
|
||||||
node = ebmb_lookup_shorter(node);
|
v4 = smp->data.u.ipv4;
|
||||||
continue;
|
goto list_lookup;
|
||||||
}
|
|
||||||
if (fill) {
|
|
||||||
static_pattern.data = elt->data;
|
|
||||||
static_pattern.ref = elt->ref;
|
|
||||||
static_pattern.sflags = PAT_SF_TREE;
|
|
||||||
static_pattern.type = SMP_T_IPV6;
|
|
||||||
memcpy(&static_pattern.val.ipv6.addr, elt->node.key, 16);
|
|
||||||
static_pattern.val.ipv6.mask = elt->node.node.pfx;
|
|
||||||
}
|
|
||||||
return &static_pattern;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The input sample is IPv6. Try to match in the trees. */
|
/* The input sample is IPv6. Try to match in the trees. */
|
||||||
if (smp->data.type == SMP_T_IPV6) {
|
if (smp->data.type == SMP_T_IPV6) {
|
||||||
/* Lookup an IPv6 address in the expression's pattern tree using
|
pattern = _pat_match_tree_ipv6(&smp->data.u.ipv6, expr, fill);
|
||||||
* the longest match method.
|
if (pattern)
|
||||||
|
return pattern;
|
||||||
|
/* No match in the IPv6 tree. Try to convert 6 to 4 to lookup in
|
||||||
|
* the IPv4 tree
|
||||||
*/
|
*/
|
||||||
node = ebmb_lookup_longest(&expr->pattern_tree_2, &smp->data.u.ipv6);
|
|
||||||
while (node) {
|
|
||||||
elt = ebmb_entry(node, struct pattern_tree, node);
|
|
||||||
if (elt->ref->gen_id != expr->ref->curr_gen) {
|
|
||||||
node = ebmb_lookup_shorter(node);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (fill) {
|
|
||||||
static_pattern.data = elt->data;
|
|
||||||
static_pattern.ref = elt->ref;
|
|
||||||
static_pattern.sflags = PAT_SF_TREE;
|
|
||||||
static_pattern.type = SMP_T_IPV6;
|
|
||||||
memcpy(&static_pattern.val.ipv6.addr, elt->node.key, 16);
|
|
||||||
static_pattern.val.ipv6.mask = elt->node.node.pfx;
|
|
||||||
}
|
|
||||||
return &static_pattern;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Try to convert 6 to 4 */
|
|
||||||
if (v6tov4(&v4, &smp->data.u.ipv6)) {
|
if (v6tov4(&v4, &smp->data.u.ipv6)) {
|
||||||
/* Lookup an IPv4 address in the expression's pattern tree using the longest
|
pattern = _pat_match_tree_ipv4(&v4, expr, fill);
|
||||||
* match method.
|
if (pattern)
|
||||||
*/
|
return pattern;
|
||||||
node = ebmb_lookup_longest(&expr->pattern_tree, &v4);
|
/* eligible for list lookup using IPv4 address */
|
||||||
while (node) {
|
goto list_lookup;
|
||||||
elt = ebmb_entry(node, struct pattern_tree, node);
|
|
||||||
if (elt->ref->gen_id != expr->ref->curr_gen) {
|
|
||||||
node = ebmb_lookup_shorter(node);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (fill) {
|
|
||||||
static_pattern.data = elt->data;
|
|
||||||
static_pattern.ref = elt->ref;
|
|
||||||
static_pattern.sflags = PAT_SF_TREE;
|
|
||||||
static_pattern.type = SMP_T_IPV4;
|
|
||||||
static_pattern.val.ipv4.addr.s_addr = read_u32(elt->node.key);
|
|
||||||
if (!cidr2dotted(elt->node.node.pfx, &static_pattern.val.ipv4.mask))
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
return &static_pattern;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Lookup in the list. the list contain only IPv4 patterns */
|
not_found:
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
list_lookup:
|
||||||
|
/* No match in the trees, but we still have a valid IPv4 address: lookup
|
||||||
|
* in the IPv4 list (non-contiguous masks list). This is our last resort
|
||||||
|
*/
|
||||||
list_for_each_entry(lst, &expr->patterns, list) {
|
list_for_each_entry(lst, &expr->patterns, list) {
|
||||||
pattern = &lst->pat;
|
pattern = &lst->pat;
|
||||||
|
|
||||||
if (pattern->ref->gen_id != expr->ref->curr_gen)
|
if (pattern->ref->gen_id != expr->ref->curr_gen)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* The input sample is IPv4, use it as is. */
|
|
||||||
if (smp->data.type == SMP_T_IPV4) {
|
|
||||||
v4.s_addr = smp->data.u.ipv4.s_addr;
|
|
||||||
}
|
|
||||||
else if (smp->data.type == SMP_T_IPV6) {
|
|
||||||
/* v4 match on a V6 sample. Try to convert v6 form to v4 address */
|
|
||||||
if (!v6tov4(&v4, &smp->data.u.ipv6))
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
/* impossible */
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check if the input sample match the current pattern. */
|
/* Check if the input sample match the current pattern. */
|
||||||
if (((v4.s_addr ^ pattern->val.ipv4.addr.s_addr) & pattern->val.ipv4.mask.s_addr) == 0)
|
if (((v4.s_addr ^ pattern->val.ipv4.addr.s_addr) & pattern->val.ipv4.mask.s_addr) == 0)
|
||||||
return pattern;
|
return pattern;
|
||||||
}
|
}
|
||||||
return NULL;
|
goto not_found;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* finds the pattern holding <list> from list head <head> and deletes it.
|
/* finds the pattern holding <list> from list head <head> and deletes it.
|
||||||
|
Loading…
Reference in New Issue
Block a user