Hi,
I've been trying to create a DPDK app that uses the ACL library and came across 
a really weird behavior.
First I thought it has to be a bug in the ACL library (see bug #79) but when I 
poked the library a bit more I
found that the matching is extremely unreliable even when having _way_ smaller 
rulesets. Thus I'm more
inclined to believe the problem lies in the way I use the library and not in 
the library itself.

I have a structure that I match on, basically a 5tuple:
```
struct fiveTuple
{
    uint8_t transportProtocol;
    uint16_t sourcePort;
    uint16_t destinationPort;
    uint32_t smth;
    IPAddress source;
    IPAddress destination;
} __rte_cache_aligned;

union ipAddress
{
    uint32_t ipv4Address;
    uint8_t  ipv6Address[16];
};
```

Then I have a rule defined in following way:
```
/* Field's indexes in rules */
enum
{
    ACL_RULE_IPV4_PROTO_FIELD,
    ACL_RULE_IPV4_SRC_FIELD,
   ACL_RULE_IPV4_FIELDS_NB
};

/* Indexes of 4-byte chunks in input */
enum
{
    ACL_RULE_IPV4_PROTO_CHUNK,
    ACL_RULE_IPV4_PORTS_CHUNK,
    ACL_RULE_IPV4_SRC_CHUNK,
};

/* IPv4 rule definition */
struct rte_acl_field_def ipv4_defs[ACL_RULE_IPV4_FIELDS_NB] = {
    {
        .type = RTE_ACL_FIELD_TYPE_BITMASK,
        .size = sizeof(uint32_t),
        .field_index = ACL_RULE_IPV4_SRC_FIELD,
        .input_index = ACL_RULE_IPV4_SRC_CHUNK,
        .offset = offsetof(struct fiveTuple, source) + offsetof(union 
ipAddress, ipv4Address),
    },
    {
        .type = RTE_ACL_FIELD_TYPE_MASK,
        .size = sizeof(uint8_t),
        .field_index = ACL_RULE_IPV4_PROTO_FIELD,
        .input_index = ACL_RULE_IPV4_PROTO_CHUNK,
        .offset = offsetof(struct fiveTuple, transportProtocol),
    },
};
```

And a function that creates these rules & adds them to context:
```
static inline void fillRule2(struct acl4_rule* rule)
{
    rule->field[ACL_RULE_IPV4_SRC_FIELD].value.u32 = IPv4(1,33,65,123);
    rule->field[ACL_RULE_IPV4_SRC_FIELD].mask_range.u32 = 0;
    rule->field[ACL_RULE_IPV4_PROTO_FIELD].value.u8 = 17;
    rule->field[ACL_RULE_IPV4_PROTO_FIELD].mask_range.u8 = -1;
    rule->data.userdata = 15;
    rule->data.category_mask = -1;
    rule->data.priority = 2;
}

static inline void fillRule1(struct acl4_rule* rule)
{
    rule->field[ACL_RULE_IPV4_SRC_FIELD].value.u32 = IPv4(0,0,0,0);
    rule->field[ACL_RULE_IPV4_SRC_FIELD].mask_range.u32 = 0;
    rule->field[ACL_RULE_IPV4_PROTO_FIELD].value.u8 = 0;
    rule->field[ACL_RULE_IPV4_PROTO_FIELD].mask_range.u8 = 0;
    rule->data.userdata = 25;
    rule->data.category_mask = -1;
    rule->data.priority = 1;
}
```

Then I create and build an ACL context with these rules. No errors are shown, 
it's dump shows two rules with appropriate size and everything.
The problem is with matching. When I send in data that should be matched by 
both rules, i.e. the one with higher priority should get returned,
the second one (rule1) gets returned even though it has lower priority.

And what's even weirder when I change rule2 in a way so it's the _same_ as 
rule1, rule1 stops matching and there're no matches reported.

Matching code:
```
    rte_acl_dump(aclCtx);
    printf("ACL for %hhu %u \n",
       *(ptrToFiveTuple + offsetof(struct fiveTuple, transportProtocol)),
       rte_be_to_cpu_32(*(uint32_t*)(ptrToFiveTuple + offsetof(struct 
fiveTuple, source)) + offsetof(union ipAddress, ipv4Address)));
    if (unlikely(rte_acl_classify(aclCtx, (const uint8_t**)(&ptrToFiveTuple), 
&result, 1, 1) != 0))
    {
        RTE_LOG(ERR, NATD, "Failed to classify a packet,\n");
        return -EINVAL;
    }
    printf("____RESULT: %u\n", result);
```

Log for the rules as they're defined above:
```
acl context <Context_1234>@0x7f1a0019c8c0
  socket_id=0
  alg=1
  max_rules=10000
  rule_size=48
  num_rules=2
  num_categories=1
  num_tries=1
ACL for 17 18956667 //18956667 is IP: 1.33.65.123
____RESULT: 25
```

Log for the situation when rule2 is changed so that it's the same as rule1:
```
{
    rule->field[ACL_RULE_IPV4_SRC_FIELD].value.u32 = IPv4(0,0,0,0);
    rule->field[ACL_RULE_IPV4_SRC_FIELD].mask_range.u32 = 0;
    rule->field[ACL_RULE_IPV4_PROTO_FIELD].value.u8 = 0;
    rule->field[ACL_RULE_IPV4_PROTO_FIELD].mask_range.u8 = 0;
    rule->data.userdata = 15;
    rule->data.category_mask = -1;
    rule->data.priority = 2;
}

```

```
acl context <Context_1234>@0x7f1a0019c8c0
  socket_id=0
  alg=1
  max_rules=10000
  rule_size=48
  num_rules=2
  num_categories=1
  num_tries=1
ACL for 17 18956667 //18956667 is IP: 1.33.65.123
____RESULT: 0
```

To be perfectly honest I have literally no idea what am I doing wrong or where 
the problem might lie. Any help would be greatly appreciated.

Petr Houska
Azure Intern

Reply via email to