Skip to content

Instantly share code, notes, and snippets.

@petrroll
Last active August 6, 2018 18:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save petrroll/5a462d65253b18b5e78c2c7efba2cb8c to your computer and use it in GitHub Desktop.
Save petrroll/5a462d65253b18b5e78c2c7efba2cb8c to your computer and use it in GitHub Desktop.
/* classifies generated packets using build contexts */
static int acl_classify(void)
{
struct rte_acl_ctx* acl_ctx = g_acl_ctx;
for (int i = 0; i < g_bench_config.classifications_nb; i++)
{
// get pointer to beginning of 5tuple in ipv4_hdr
const uint8_t* packet_5tuple_hdr = ((const uint8_t*)packet_ctx->ipv4header + OFF_IPV42PROTO);
u_int32_t result;
// classify packet using ACL context and 5tuple
if (unlikely(rte_acl_classify(vni_acl_ctx, &packet_5tuple_hdr, &result, 1, 1) != 0))
rte_exit(EXIT_FAILURE, "Failed to classify packet.\n");
#ifdef DEBUG
if (g_bench_config.d_classification)
{
printf("%i\t%i |", i % g_gen_packets.packets_nb, result);
print_one_ipv4_ctxhdr(packet_ctx);
}
#endif // DEBUG
}
return 0;
}
# The second number of the PACKET_MATCH row is result -> matched id. If it's -1 the catch-all rule matched. If it's 0 no rule matched.
make && sudo time ./build/app/acl-bench -- -r 10000 -c 1 -p 1 -n 1 -m -t
Rules number: 100
Contexts rebuilds: 1
Packets number: 1
Classifications number: 1
IPv4 ACL entries 100:
...
RULE: 10000:1.33.65.123/4 17.9.123.145/0 1:65535 1:65535 0x11/0xff 0xffffffff |0|-1|
PACKET_MATCH: 0 0 |0|1.33.65.123:10083 -> 17.9.123.145:40757 | 17
make && sudo time ./build/app/acl-bench -- -r 1000 -c 1 -p 1 -n 1 -m -t
Rules number: 1000
Contexts rebuilds: 1
Packets number: 1
Classifications number: 1
IPv4 ACL entries 1000:
...
RULE: 1000:1.33.65.123/4 17.9.123.145/0 1:65535 1:65535 0x11/0xff 0xffffffff |0|-1|
PACKET_MATCH: 0 -1 |0|1.33.65.123:10083 -> 17.9.123.145:40757 | 17
static inline void fill_ipv4_hdr_portswrap(struct ipv4_hdr_portswrap* hdr, uint8_t proto_id, uint32_t src_addr, uint32_t dst_addr, uint16_t src_port, uint16_t dst_port)
{
hdr->ipv4hdr.next_proto_id = proto_id;
// change bits to network order
hdr->ipv4hdr.src_addr = rte_bswap32(src_addr);
hdr->ipv4hdr.dst_addr = rte_bswap32(dst_addr);
hdr->src_port = rte_bswap16(src_port);
hdr->dst_port = rte_bswap16(dst_port);
}
/* Generates a random ipv4 packet header + subsequent TCP/UDP port info */
static int generate_ipv4_hdr_portswrap(struct ipv4_hdr_portswrap* hdr, int i)
{
UNUSED(i);
fill_ipv4_hdr_portswrap(
hdr, 17,
rand_ipv4(), rand_ipv4(),
rand_max(1 << 16), rand_max(1 << 16));
// rewrite the randomly generated packet with my own specified one that should always get matched by the catch_all rule //
fill_ipv4_hdr_portswrap(
hdr, 17,
IPv4(1,33,65,123), IPv4(17,9,123,145),
10083, 40757);
return 0;
}
#pragma once
#include <rte_ip.h>
#define OFF_IPV42PROTO (offsetof(struct ipv4_hdr, next_proto_id))
#define MBUF_IPV4_2PROTO(m) \
rte_pktmbuf_mtod_offset((m), uint8_t *, OFF_IPV42PROTO)
/* Wrapper around ipv4_hdr structure that adds subsequent fields for src/dst ports.
* Contains all packet data required for ACL matching.
*/
struct ipv4_hdr_portswrap {
struct ipv4_hdr ipv4hdr;
uint16_t src_port;
uint16_t dst_port;
} __attribute__((__packed__));
/* Field index in rule*/
enum {
PROTO_FIELD_IPV4,
SRC_FIELD_IPV4,
DST_FIELD_IPV4,
SRCP_FIELD_IPV4,
DSTP_FIELD_IPV4,
NUM_FIELDS_IPV4
};
/*
* Defines what 4-byte chunks in input the fields belong to.
* - PROTO
* - VLAN (TAG and DOMAIN)
* - SRC IP ADDRESS
* - DST IP ADDRESS
* - PORTS (SRC and DST)
*/
enum {
RTE_ACL_IPV4VLAN_PROTO,
RTE_ACL_IPV4VLAN_VLAN,
RTE_ACL_IPV4VLAN_SRC,
RTE_ACL_IPV4VLAN_DST,
RTE_ACL_IPV4VLAN_PORTS,
RTE_ACL_IPV4VLAN_NUM
};
struct rte_acl_field_def ipv4_defs[NUM_FIELDS_IPV4] = {
{
.type = RTE_ACL_FIELD_TYPE_BITMASK,
.size = sizeof(uint8_t),
.field_index = PROTO_FIELD_IPV4,
.input_index = RTE_ACL_IPV4VLAN_PROTO,
.offset = 0,
},
{
.type = RTE_ACL_FIELD_TYPE_MASK,
.size = sizeof(uint32_t),
.field_index = SRC_FIELD_IPV4,
.input_index = RTE_ACL_IPV4VLAN_SRC,
.offset = offsetof(struct ipv4_hdr, src_addr) -
offsetof(struct ipv4_hdr, next_proto_id),
},
{
.type = RTE_ACL_FIELD_TYPE_MASK,
.size = sizeof(uint32_t),
.field_index = DST_FIELD_IPV4,
.input_index = RTE_ACL_IPV4VLAN_DST,
.offset = offsetof(struct ipv4_hdr, dst_addr) -
offsetof(struct ipv4_hdr, next_proto_id),
},
{
.type = RTE_ACL_FIELD_TYPE_RANGE,
.size = sizeof(uint16_t),
.field_index = SRCP_FIELD_IPV4,
.input_index = RTE_ACL_IPV4VLAN_PORTS,
.offset = sizeof(struct ipv4_hdr) -
offsetof(struct ipv4_hdr, next_proto_id),
},
{
.type = RTE_ACL_FIELD_TYPE_RANGE,
.size = sizeof(uint16_t),
.field_index = DSTP_FIELD_IPV4,
.input_index = RTE_ACL_IPV4VLAN_PORTS,
.offset = sizeof(struct ipv4_hdr) -
offsetof(struct ipv4_hdr, next_proto_id) +
sizeof(uint16_t),
},
};
RTE_ACL_RULE_DEF(acl4_rule, NUM_FIELDS_IPV4);
/* Allocates array & populates it with generated rules. */
static int add_rules(struct rte_acl_rule** acl_base, int* acl_num, int (*generate_rule)(struct rte_acl_rule*, int i), uint32_t rule_size)
{
struct rte_acl_rule* rules = NULL;
int rules_num = g_bench_config.rules_nb;
rules = calloc(rules_num, rule_size);
if (rules == NULL)
rte_exit(EXIT_FAILURE, "Couldn't allocate enough to generate rules.\n");
// generate random rules
struct rte_acl_rule* rule_slot = NULL;
for(int i = 0; i < rules_num - 1; i++) // don't generate last rule -> special one that catches everything
{
rule_slot = (struct rte_acl_rule *)((uint8_t*)(rules) + i * rule_size); //uint8_t cast -> the (i * rule_size) addition is interpreted in bytes
generate_rule(rule_slot, i);
rule_slot->data.priority = (i + 1);
rule_slot->data.category_mask = -1;
}
// generate rule that captures all packets
rule_slot = (struct rte_acl_rule *)((uint8_t*)(rules)+(rules_num - 1) * rule_size); //uint8_t cast -> the (i * rule_size) addition is interpreted in bytes
generate_rule_catch_all(rule_slot, -2); // -2 -> -1 to user.data -> max number
rule_slot->data.priority = RTE_ACL_MIN_PRIORITY;
rule_slot->data.category_mask = -1;
*acl_base = rules;
*acl_num = rules_num;
return 0;
}
/*
* Rule generator.
*/
static inline void fill_rule(struct rte_acl_rule* rule,
uint32_t src_address, uint32_t src_address_mask,
uint32_t dst_address, uint32_t dst_address_mask,
uint16_t src_port_min, uint16_t src_port_max,
uint16_t dst_port_min, uint16_t dst_port_max,
uint16_t protocol, uint16_t protocol_mask,
uint32_t usr_data)
{
rule->field[SRC_FIELD_IPV4].value.u32 = src_address;
rule->field[SRC_FIELD_IPV4].mask_range.u32 = src_address_mask;
rule->field[DST_FIELD_IPV4].value.u32 = dst_address;
rule->field[DST_FIELD_IPV4].mask_range.u32 = dst_address_mask;
rule->field[SRCP_FIELD_IPV4].value.u16 = src_port_min; //range -> low
rule->field[SRCP_FIELD_IPV4].mask_range.u16 = src_port_max; //range -> high
rule->field[DSTP_FIELD_IPV4].value.u16 = dst_port_min; //range -> low
rule->field[DSTP_FIELD_IPV4].mask_range.u16 = dst_port_max; //range -> high
rule->field[PROTO_FIELD_IPV4].value.u16 = protocol;
rule->field[PROTO_FIELD_IPV4].mask_range.u16 = protocol_mask;
rule->data.userdata = usr_data;
}
int generate_rule(struct rte_acl_rule* rule, int i)
{
uint16_t src_port = rand_max(1 << 16);
uint16_t dst_port = rand_max(1 << 16);
fill_rule(rule,
rand_ipv4(), rand_max(32),
rand_ipv4(), rand_max(32),
src_port, rand_min_max(src_port, 1 << 16),
dst_port, rand_min_max(dst_port, 1 << 16),
17, -1,
(i + 1));
return 0;
}
int generate_rule_catch_all(struct rte_acl_rule* rule, int i)
{
UNUSED(i);
fill_rule(rule,
IPv4(1, 33, 65, 123), 4, //the lower the mask is the less rules there can be for the matching to actually work
IPv4(17, 9, 123, 145), 0,
1, (1 << 16) - 1,
1, (1 << 16) - 1,
17, -1,
-1);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment