examples/l3fwd: support config file for EM

Add support to define ipv4 and ipv6 forwarding tables
from reading from a config file for EM with a format
similar to l3fwd-acl one.

Users can now use the default hardcoded route tables
or optionally config files for 'l3fwd_em'. Default
config files have been provided for use with EM.

Related l3fwd docs have been updated to reflect these
changes.

Signed-off-by: Sean Morrissey <sean.morrissey@intel.com>
Acked-by: Konstantin Ananyev <konstantin.ananyev@intel.com>
This commit is contained in:
Sean Morrissey 2022-03-01 14:49:08 +00:00 committed by Thomas Monjalon
parent 52def963fc
commit e7e6dd6430
6 changed files with 479 additions and 167 deletions

View File

@ -47,6 +47,7 @@ and loaded into the LPM or FIB object at initialization time.
In the sample application, hash-based and FIB-based forwarding supports In the sample application, hash-based and FIB-based forwarding supports
both IPv4 and IPv6. both IPv4 and IPv6.
LPM-based forwarding supports IPv4 only. LPM-based forwarding supports IPv4 only.
During the initialization phase route rules for IPv4 and IPv6 are read from rule files.
Compiling the Application Compiling the Application
------------------------- -------------------------
@ -61,6 +62,8 @@ Running the Application
The application has a number of command line options:: The application has a number of command line options::
./dpdk-l3fwd [EAL options] -- -p PORTMASK ./dpdk-l3fwd [EAL options] -- -p PORTMASK
--rule_ipv4=FILE
--rule_ipv6=FILE
[-P] [-P]
[--lookup LOOKUP_METHOD] [--lookup LOOKUP_METHOD]
--config(port,queue,lcore)[,(port,queue,lcore)] --config(port,queue,lcore)[,(port,queue,lcore)]
@ -82,6 +85,11 @@ Where,
* ``-p PORTMASK:`` Hexadecimal bitmask of ports to configure * ``-p PORTMASK:`` Hexadecimal bitmask of ports to configure
* ``--rule_ipv4=FILE:`` specify the ipv4 rules entries file.
Each rule occupies one line.
* ``--rule_ipv6=FILE:`` specify the ipv6 rules entries file.
* ``-P:`` Optional, sets all ports to promiscuous mode so that packets are accepted regardless of the packet's Ethernet MAC destination address. * ``-P:`` Optional, sets all ports to promiscuous mode so that packets are accepted regardless of the packet's Ethernet MAC destination address.
Without this option, only packets with the Ethernet MAC destination address set to the Ethernet address of the port are accepted. Without this option, only packets with the Ethernet MAC destination address set to the Ethernet address of the port are accepted.
@ -135,7 +143,7 @@ To enable L3 forwarding between two ports, assuming that both ports are in the s
.. code-block:: console .. code-block:: console
./<build_dir>/examples/dpdk-l3fwd -l 1,2 -n 4 -- -p 0x3 --config="(0,0,1),(1,0,2)" ./<build_dir>/examples/dpdk-l3fwd -l 1,2 -n 4 -- -p 0x3 --config="(0,0,1),(1,0,2)" --rule_ipv4="rule_ipv4.cfg" --rule_ipv6="rule_ipv6.cfg"
In this command: In this command:
@ -157,19 +165,23 @@ In this command:
| | | | | | | | | |
+----------+-----------+-----------+-------------------------------------+ +----------+-----------+-----------+-------------------------------------+
* The -rule_ipv4 option specifies the reading of IPv4 rules sets from the rule_ipv4.cfg file
* The -rule_ipv6 option specifies the reading of IPv6 rules sets from the rule_ipv6.cfg file.
To use eventdev mode with sync method **ordered** on above mentioned environment, To use eventdev mode with sync method **ordered** on above mentioned environment,
Following is the sample command: Following is the sample command:
.. code-block:: console .. code-block:: console
./<build_dir>/examples/dpdk-l3fwd -l 0-3 -n 4 -a <event device> -- -p 0x3 --eventq-sched=ordered ./<build_dir>/examples/dpdk-l3fwd -l 0-3 -n 4 -a <event device> -- -p 0x3 --eventq-sched=ordered --rule_ipv4="rule_ipv4.cfg" --rule_ipv6="rule_ipv6.cfg"
or or
.. code-block:: console .. code-block:: console
./<build_dir>/examples/dpdk-l3fwd -l 0-3 -n 4 -a <event device> \ ./<build_dir>/examples/dpdk-l3fwd -l 0-3 -n 4 -a <event device> \
-- -p 0x03 --mode=eventdev --eventq-sched=ordered -- -p 0x03 --mode=eventdev --eventq-sched=ordered --rule_ipv4="rule_ipv4.cfg" --rule_ipv6="rule_ipv6.cfg"
In this command: In this command:
@ -192,7 +204,7 @@ scheduler. Following is the sample command:
.. code-block:: console .. code-block:: console
./<build_dir>/examples/dpdk-l3fwd -l 0-7 -s 0xf0000 -n 4 --vdev event_sw0 -- -p 0x3 --mode=eventdev --eventq-sched=ordered ./<build_dir>/examples/dpdk-l3fwd -l 0-7 -s 0xf0000 -n 4 --vdev event_sw0 -- -p 0x3 --mode=eventdev --eventq-sched=ordered --rule_ipv4="rule_ipv4.cfg" --rule_ipv6="rule_ipv6.cfg"
In case of eventdev mode, *--config* option is not used for ethernet port In case of eventdev mode, *--config* option is not used for ethernet port
configuration. Instead each ethernet port will be configured with mentioned configuration. Instead each ethernet port will be configured with mentioned
@ -216,6 +228,49 @@ The following sections provide some explanation of the sample application code.
the initialization and run-time paths are very similar to those of the :doc:`l2_forward_real_virtual` and :doc:`l2_forward_event`. the initialization and run-time paths are very similar to those of the :doc:`l2_forward_real_virtual` and :doc:`l2_forward_event`.
The following sections describe aspects that are specific to the L3 Forwarding sample application. The following sections describe aspects that are specific to the L3 Forwarding sample application.
Parse Rules from File
~~~~~~~~~~~~~~~~~~~~~
The application parses the rules from the file and adds them to the appropriate route table by calling the appropriate function.
It ignores empty and comment lines, and parses and validates the rules it reads.
If errors are detected, the application exits with messages to identify the errors encountered.
The format of the route rules differs based on which lookup method is being used.
Therefore, the code only decreases the priority number with each rule it parses.
Route rules are mandatory.
To read data from the specified file successfully, the application assumes the following:
* Each rule occupies a single line.
* Only the following four rule line types are valid in this application:
* Route rule line, which starts with a leading character 'R'
* Comment line, which starts with a leading character '#'
* Empty line, which consists of a space, form-feed ('\f'), newline ('\n'),
carriage return ('\r'), horizontal tab ('\t'), or vertical tab ('\v').
Other lines types are considered invalid.
* Rules are organized in descending order of priority,
which means rules at the head of the file always have a higher priority than those further down in the file.
* A typical IPv4 LPM/FIB rule line should have a format as shown below:
R<destination_ip>/<ip_mask_length><output_port_number>
* A typical IPv4 EM rule line should have a format as shown below:
R<destination_ip><source_ip><destination_port><source_port><protocol><output_port_number>
IPv4 addresses are specified in CIDR format as specified in RFC 4632.
For LPM/FIB they consist of the dot notation for the address and a prefix length separated by '/'.
For example, 192.168.0.34/32, where the address is 192.168.0.34 and the prefix length is 32.
For EM they consist of just the dot notation for the address and no prefix length.
For example, 192.168.0.34, where the Address is 192.168.0.34.
EM also includes ports which are specified as a single number which represents a single port.
Hash Initialization Hash Initialization
~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~
@ -227,8 +282,6 @@ for the convenience to execute hash performance test on 4M/8M/16M flows.
The Hash initialization will setup both ipv4 and ipv6 hash table, The Hash initialization will setup both ipv4 and ipv6 hash table,
and populate the either table depending on the value of variable ipv6. and populate the either table depending on the value of variable ipv6.
To support the hash performance test with up to 8M single direction flows/16M bi-direction flows,
populate_ipv4_many_flow_into_table() function will populate the hash table with specified hash table entry number(default 4M).
.. note:: .. note::
@ -246,22 +299,14 @@ for the convenience to execute hash performance test on 4M/8M/16M flows.
{ {
// ... // ...
if (hash_entry_number != HASH_ENTRY_NUMBER_DEFAULT) { if (ipv6 == 0) {
if (ipv6 == 0) { /* populate the ipv4 hash */
/* populate the ipv4 hash */ populate_ipv4_flow_into_table(
populate_ipv4_many_flow_into_table(ipv4_l3fwd_lookup_struct[socketid], hash_entry_number); ipv4_l3fwd_em_lookup_struct[socketid]);
} else { } else {
/* populate the ipv6 hash */ /* populate the ipv6 hash */
populate_ipv6_many_flow_into_table( ipv6_l3fwd_lookup_struct[socketid], hash_entry_number); populate_ipv6_flow_into_table(
} ipv6_l3fwd_em_lookup_struct[socketid]);
} else
if (ipv6 == 0) {
/* populate the ipv4 hash */
populate_ipv4_few_flow_into_table(ipv4_l3fwd_lookup_struct[socketid]);
} else {
/* populate the ipv6 hash */
populate_ipv6_few_flow_into_table(ipv6_l3fwd_lookup_struct[socketid]);
}
} }
} }
#endif #endif

View File

@ -0,0 +1,17 @@
#Copy of hard-coded IPv4 FWD table for L3FWD EM
R198.18.0.0 198.18.0.1 9 9 0x11 0
R198.18.1.0 198.18.1.1 9 9 0x11 1
R198.18.2.0 198.18.2.1 9 9 0x11 2
R198.18.3.0 198.18.3.1 9 9 0x11 3
R198.18.4.0 198.18.4.1 9 9 0x11 4
R198.18.5.0 198.18.5.1 9 9 0x11 5
R198.18.6.0 198.18.6.1 9 9 0x11 6
R198.18.7.0 198.18.7.1 9 9 0x11 7
R198.18.8.0 198.18.8.1 9 9 0x11 8
R198.18.9.0 198.18.9.1 9 9 0x11 9
R198.18.10.0 198.18.10.1 9 9 0x11 10
R198.18.11.0 198.18.11.1 9 9 0x11 11
R198.18.12.0 198.18.12.1 9 9 0x11 12
R198.18.13.0 198.18.13.1 9 9 0x11 13
R198.18.14.0 198.18.14.1 9 9 0x11 14
R198.18.15.0 198.18.15.1 9 9 0x11 15

View File

@ -0,0 +1,17 @@
#Copy of hard-coded IPv6 FWD table for L3FWD EM
R2001:0200:0000:0000:0000:0000:0000:0000 2001:0200:0000:0000:0000:0000:0000:0001 9 9 0x11 0
R2001:0200:0000:0001:0000:0000:0000:0000 2001:0200:0000:0001:0000:0000:0000:0001 9 9 0x11 1
R2001:0200:0000:0002:0000:0000:0000:0000 2001:0200:0000:0002:0000:0000:0000:0001 9 9 0x11 2
R2001:0200:0000:0003:0000:0000:0000:0000 2001:0200:0000:0003:0000:0000:0000:0001 9 9 0x11 3
R2001:0200:0000:0004:0000:0000:0000:0000 2001:0200:0000:0004:0000:0000:0000:0001 9 9 0x11 4
R2001:0200:0000:0005:0000:0000:0000:0000 2001:0200:0000:0005:0000:0000:0000:0001 9 9 0x11 5
R2001:0200:0000:0006:0000:0000:0000:0000 2001:0200:0000:0006:0000:0000:0000:0001 9 9 0x11 6
R2001:0200:0000:0007:0000:0000:0000:0000 2001:0200:0000:0007:0000:0000:0000:0001 9 9 0x11 7
R2001:0200:0000:0008:0000:0000:0000:0000 2001:0200:0000:0008:0000:0000:0000:0001 9 9 0x11 8
R2001:0200:0000:0009:0000:0000:0000:0000 2001:0200:0000:0009:0000:0000:0000:0001 9 9 0x11 9
R2001:0200:0000:000A:0000:0000:0000:0000 2001:0200:0000:000A:0000:0000:0000:0001 9 9 0x11 10
R2001:0200:0000:000B:0000:0000:0000:0000 2001:0200:0000:000B:0000:0000:0000:0001 9 9 0x11 11
R2001:0200:0000:000C:0000:0000:0000:0000 2001:0200:0000:000C:0000:0000:0000:0001 9 9 0x11 12
R2001:0200:0000:000D:0000:0000:0000:0000 2001:0200:0000:000D:0000:0000:0000:0001 9 9 0x11 13
R2001:0200:0000:000E:0000:0000:0000:0000 2001:0200:0000:000E:0000:0000:0000:0001 9 9 0x11 14
R2001:0200:0000:000F:0000:0000:0000:0000 2001:0200:0000:000F:0000:0000:0000:0001 9 9 0x11 15

View File

@ -2,17 +2,279 @@
* Copyright(c) 2022 Intel Corporation * Copyright(c) 2022 Intel Corporation
*/ */
#include <stdio.h>
#include <stdint.h>
#include <errno.h>
#include <sys/socket.h>
#include "l3fwd.h"
#include "l3fwd_route.h" #include "l3fwd_route.h"
static struct em_rule *em_route_base_v4;
static struct em_rule *em_route_base_v6;
enum {
CB_FLD_DST_ADDR,
CB_FLD_SRC_ADDR,
CB_FLD_DST_PORT,
CB_FLD_SRC_PORT,
CB_FLD_PROTO,
CB_FLD_IF_OUT,
CB_FLD_MAX
};
static int
em_parse_v6_net(const char *in, uint8_t *v)
{
int32_t rc;
/* get address. */
rc = inet_pton(AF_INET6, in, v);
if (rc != 1)
return -EINVAL;
return 0;
}
static int
em_parse_v6_rule(char *str, struct em_rule *v)
{
int i, rc;
char *s, *sp, *in[CB_FLD_MAX];
static const char *dlm = " \t\n";
int dim = CB_FLD_MAX;
s = str;
for (i = 0; i != dim; i++, s = NULL) {
in[i] = strtok_r(s, dlm, &sp);
if (in[i] == NULL)
return -EINVAL;
}
rc = em_parse_v6_net(in[CB_FLD_DST_ADDR], v->v6_key.ip_dst);
if (rc != 0)
return rc;
rc = em_parse_v6_net(in[CB_FLD_SRC_ADDR], v->v6_key.ip_src);
if (rc != 0)
return rc;
/* source port. */
GET_CB_FIELD(in[CB_FLD_SRC_PORT], v->v6_key.port_src, 0, UINT16_MAX, 0);
/* destination port. */
GET_CB_FIELD(in[CB_FLD_DST_PORT], v->v6_key.port_dst, 0, UINT16_MAX, 0);
/* protocol. */
GET_CB_FIELD(in[CB_FLD_PROTO], v->v6_key.proto, 0, UINT8_MAX, 0);
/* out interface. */
GET_CB_FIELD(in[CB_FLD_IF_OUT], v->if_out, 0, UINT8_MAX, 0);
return 0;
}
static int
em_parse_v4_rule(char *str, struct em_rule *v)
{
int i, rc;
char *s, *sp, *in[CB_FLD_MAX];
static const char *dlm = " \t\n";
int dim = CB_FLD_MAX;
s = str;
for (i = 0; i != dim; i++, s = NULL) {
in[i] = strtok_r(s, dlm, &sp);
if (in[i] == NULL)
return -EINVAL;
}
rc = inet_pton(AF_INET, in[CB_FLD_DST_ADDR], &(v->v4_key.ip_dst));
v->v4_key.ip_dst = ntohl(v->v4_key.ip_dst);
if (rc != 1)
return rc;
rc = inet_pton(AF_INET, in[CB_FLD_SRC_ADDR], &(v->v4_key.ip_src));
v->v4_key.ip_src = ntohl(v->v4_key.ip_src);
if (rc != 1)
return rc;
/* source port. */
GET_CB_FIELD(in[CB_FLD_SRC_PORT], v->v4_key.port_src, 0, UINT16_MAX, 0);
/* destination port. */
GET_CB_FIELD(in[CB_FLD_DST_PORT], v->v4_key.port_dst, 0, UINT16_MAX, 0);
/* protocol. */
GET_CB_FIELD(in[CB_FLD_PROTO], v->v4_key.proto, 0, UINT8_MAX, 0);
/* out interface. */
GET_CB_FIELD(in[CB_FLD_IF_OUT], v->if_out, 0, UINT8_MAX, 0);
return 0;
}
static int
em_add_rules(const char *rule_path,
struct em_rule **proute_base,
int (*parser)(char *, struct em_rule *))
{
struct em_rule *route_rules;
struct em_rule *next;
unsigned int route_num = 0;
unsigned int route_cnt = 0;
char buff[LINE_MAX];
FILE *fh;
unsigned int i = 0, rule_size = sizeof(*next);
int val;
*proute_base = NULL;
fh = fopen(rule_path, "rb");
if (fh == NULL)
return -EINVAL;
while ((fgets(buff, LINE_MAX, fh) != NULL)) {
if (buff[0] == ROUTE_LEAD_CHAR)
route_num++;
}
if (route_num == 0) {
fclose(fh);
return -EINVAL;
}
val = fseek(fh, 0, SEEK_SET);
if (val < 0) {
fclose(fh);
return -EINVAL;
}
route_rules = calloc(route_num, rule_size);
if (route_rules == NULL) {
fclose(fh);
return -EINVAL;
}
i = 0;
while (fgets(buff, LINE_MAX, fh) != NULL) {
i++;
if (is_bypass_line(buff))
continue;
char s = buff[0];
/* Route entry */
if (s == ROUTE_LEAD_CHAR)
next = &route_rules[route_cnt];
/* Illegal line */
else {
RTE_LOG(ERR, L3FWD,
"%s Line %u: should start with leading "
"char %c\n",
rule_path, i, ROUTE_LEAD_CHAR);
fclose(fh);
free(route_rules);
return -EINVAL;
}
if (parser(buff + 1, next) != 0) {
RTE_LOG(ERR, L3FWD,
"%s Line %u: parse rules error\n",
rule_path, i);
fclose(fh);
free(route_rules);
return -EINVAL;
}
route_cnt++;
}
fclose(fh);
*proute_base = route_rules;
return route_cnt;
}
static int
em_add_default_v4_rules(void)
{
/* populate the LPM IPv4 table */
unsigned int i, rule_size = sizeof(*em_route_base_v4);
route_num_v4 = RTE_DIM(ipv4_l3fwd_em_route_array);
em_route_base_v4 = calloc(route_num_v4, rule_size);
for (i = 0; i < (unsigned int)route_num_v4; i++) {
em_route_base_v4[i].v4_key.ip_dst = ipv4_l3fwd_em_route_array[i].key.ip_dst;
em_route_base_v4[i].v4_key.ip_src = ipv4_l3fwd_em_route_array[i].key.ip_src;
em_route_base_v4[i].v4_key.port_dst = ipv4_l3fwd_em_route_array[i].key.port_dst;
em_route_base_v4[i].v4_key.port_src = ipv4_l3fwd_em_route_array[i].key.port_src;
em_route_base_v4[i].v4_key.proto = ipv4_l3fwd_em_route_array[i].key.proto;
em_route_base_v4[i].if_out = ipv4_l3fwd_em_route_array[i].if_out;
}
return 0;
}
static int
em_add_default_v6_rules(void)
{
/* populate the LPM IPv6 table */
unsigned int i, rule_size = sizeof(*em_route_base_v6);
route_num_v6 = RTE_DIM(ipv6_l3fwd_em_route_array);
em_route_base_v6 = calloc(route_num_v6, rule_size);
for (i = 0; i < (unsigned int)route_num_v6; i++) {
memcpy(em_route_base_v6[i].v6_key.ip_dst, ipv6_l3fwd_em_route_array[i].key.ip_dst,
sizeof(em_route_base_v6[i].v6_key.ip_dst));
memcpy(em_route_base_v6[i].v6_key.ip_src, ipv6_l3fwd_em_route_array[i].key.ip_src,
sizeof(em_route_base_v6[i].v6_key.ip_src));
em_route_base_v6[i].v6_key.port_dst = ipv6_l3fwd_em_route_array[i].key.port_dst;
em_route_base_v6[i].v6_key.port_src = ipv6_l3fwd_em_route_array[i].key.port_src;
em_route_base_v6[i].v6_key.proto = ipv6_l3fwd_em_route_array[i].key.proto;
em_route_base_v6[i].if_out = ipv6_l3fwd_em_route_array[i].if_out;
}
return 0;
}
void void
em_free_routes(void) em_free_routes(void)
{ {
/* Empty till config file support added to EM */ free(em_route_base_v4);
free(em_route_base_v6);
em_route_base_v4 = NULL;
em_route_base_v6 = NULL;
route_num_v4 = 0;
route_num_v6 = 0;
} }
/* Load rules from the input file */ /* Load rules from the input file */
void void
read_config_files_em(void) read_config_files_em(void)
{ {
/* Empty till config file support added to EM */ /* ipv4 check */
if (parm_config.rule_ipv4_name != NULL &&
parm_config.rule_ipv6_name != NULL) {
/* ipv4 check */
route_num_v4 = em_add_rules(parm_config.rule_ipv4_name,
&em_route_base_v4, &em_parse_v4_rule);
if (route_num_v4 < 0) {
em_free_routes();
rte_exit(EXIT_FAILURE, "Failed to add EM IPv4 rules\n");
}
/* ipv6 check */
route_num_v6 = em_add_rules(parm_config.rule_ipv6_name,
&em_route_base_v6, &em_parse_v6_rule);
if (route_num_v6 < 0) {
em_free_routes();
rte_exit(EXIT_FAILURE, "Failed to add EM IPv6 rules\n");
}
} else {
RTE_LOG(INFO, L3FWD, "Missing 1 or more rule files, using default instead\n");
if (em_add_default_v4_rules() < 0) {
em_free_routes();
rte_exit(EXIT_FAILURE, "Failed to add default IPv4 rules\n");
}
if (em_add_default_v6_rules() < 0) {
em_free_routes();
rte_exit(EXIT_FAILURE, "Failed to add default IPv6 rules\n");
}
}
} }

View File

@ -43,14 +43,6 @@
#define IPV6_ADDR_LEN 16 #define IPV6_ADDR_LEN 16
struct ipv4_5tuple {
uint32_t ip_dst;
uint32_t ip_src;
uint16_t port_dst;
uint16_t port_src;
uint8_t proto;
} __rte_packed;
union ipv4_5tuple_host { union ipv4_5tuple_host {
struct { struct {
uint8_t pad0; uint8_t pad0;
@ -66,14 +58,6 @@ union ipv4_5tuple_host {
#define XMM_NUM_IN_IPV6_5TUPLE 3 #define XMM_NUM_IN_IPV6_5TUPLE 3
struct ipv6_5tuple {
uint8_t ip_dst[IPV6_ADDR_LEN];
uint8_t ip_src[IPV6_ADDR_LEN];
uint16_t port_dst;
uint16_t port_src;
uint8_t proto;
} __rte_packed;
union ipv6_5tuple_host { union ipv6_5tuple_host {
struct { struct {
uint16_t pad0; uint16_t pad0;
@ -88,22 +72,10 @@ union ipv6_5tuple_host {
xmm_t xmm[XMM_NUM_IN_IPV6_5TUPLE]; xmm_t xmm[XMM_NUM_IN_IPV6_5TUPLE];
}; };
struct ipv4_l3fwd_em_route {
struct ipv4_5tuple key;
uint8_t if_out;
};
struct ipv6_l3fwd_em_route {
struct ipv6_5tuple key;
uint8_t if_out;
};
/* 198.18.0.0/16 are set aside for RFC2544 benchmarking (RFC5735). /* 198.18.0.0/16 are set aside for RFC2544 benchmarking (RFC5735).
* Use RFC863 Discard Protocol. * Use RFC863 Discard Protocol.
*/ */
static const struct ipv4_l3fwd_em_route ipv4_l3fwd_em_route_array[] = { const struct ipv4_l3fwd_em_route ipv4_l3fwd_em_route_array[] = {
{{RTE_IPV4(198, 18, 0, 0), RTE_IPV4(198, 18, 0, 1), 9, 9, IPPROTO_UDP}, 0}, {{RTE_IPV4(198, 18, 0, 0), RTE_IPV4(198, 18, 0, 1), 9, 9, IPPROTO_UDP}, 0},
{{RTE_IPV4(198, 18, 1, 0), RTE_IPV4(198, 18, 1, 1), 9, 9, IPPROTO_UDP}, 1}, {{RTE_IPV4(198, 18, 1, 0), RTE_IPV4(198, 18, 1, 1), 9, 9, IPPROTO_UDP}, 1},
{{RTE_IPV4(198, 18, 2, 0), RTE_IPV4(198, 18, 2, 1), 9, 9, IPPROTO_UDP}, 2}, {{RTE_IPV4(198, 18, 2, 0), RTE_IPV4(198, 18, 2, 1), 9, 9, IPPROTO_UDP}, 2},
@ -125,7 +97,7 @@ static const struct ipv4_l3fwd_em_route ipv4_l3fwd_em_route_array[] = {
/* 2001:0200::/48 is IANA reserved range for IPv6 benchmarking (RFC5180). /* 2001:0200::/48 is IANA reserved range for IPv6 benchmarking (RFC5180).
* Use RFC863 Discard Protocol. * Use RFC863 Discard Protocol.
*/ */
static const struct ipv6_l3fwd_em_route ipv6_l3fwd_em_route_array[] = { const struct ipv6_l3fwd_em_route ipv6_l3fwd_em_route_array[] = {
{{{32, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {{{32, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{32, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, 9, 9, IPPROTO_UDP}, 0}, {32, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, 9, 9, IPPROTO_UDP}, 0},
{{{32, 1, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0}, {{{32, 1, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0},
@ -236,10 +208,6 @@ ipv6_hash_crc(const void *data, __rte_unused uint32_t data_len,
return init_val; return init_val;
} }
#define IPV4_L3FWD_EM_NUM_ROUTES RTE_DIM(ipv4_l3fwd_em_route_array)
#define IPV6_L3FWD_EM_NUM_ROUTES RTE_DIM(ipv6_l3fwd_em_route_array)
static uint8_t ipv4_l3fwd_out_if[L3FWD_HASH_ENTRIES] __rte_cache_aligned; static uint8_t ipv4_l3fwd_out_if[L3FWD_HASH_ENTRIES] __rte_cache_aligned;
static uint8_t ipv6_l3fwd_out_if[L3FWD_HASH_ENTRIES] __rte_cache_aligned; static uint8_t ipv6_l3fwd_out_if[L3FWD_HASH_ENTRIES] __rte_cache_aligned;
@ -383,122 +351,106 @@ convert_ipv6_5tuple(struct ipv6_5tuple *key1,
#define BIT_8_TO_15 0x0000ff00 #define BIT_8_TO_15 0x0000ff00
static inline void static inline void
populate_ipv4_few_flow_into_table(const struct rte_hash *h) populate_ipv4_flow_into_table(const struct rte_hash *h)
{ {
uint32_t i; int i;
int32_t ret; int32_t ret;
struct rte_eth_dev_info dev_info;
char srcbuf[INET6_ADDRSTRLEN];
char dstbuf[INET6_ADDRSTRLEN];
mask0 = (rte_xmm_t){.u32 = {BIT_8_TO_15, ALL_32_BITS, mask0 = (rte_xmm_t){.u32 = {BIT_8_TO_15, ALL_32_BITS,
ALL_32_BITS, ALL_32_BITS} }; ALL_32_BITS, ALL_32_BITS} };
for (i = 0; i < IPV4_L3FWD_EM_NUM_ROUTES; i++) { for (i = 0; i < route_num_v4; i++) {
struct ipv4_l3fwd_em_route entry; struct em_rule *entry;
union ipv4_5tuple_host newkey; union ipv4_5tuple_host newkey;
struct in_addr src;
struct in_addr dst;
entry = ipv4_l3fwd_em_route_array[i]; if ((1 << em_route_base_v4[i].if_out &
convert_ipv4_5tuple(&entry.key, &newkey); enabled_port_mask) == 0)
continue;
entry = &em_route_base_v4[i];
convert_ipv4_5tuple(&(entry->v4_key), &newkey);
ret = rte_hash_add_key(h, (void *) &newkey); ret = rte_hash_add_key(h, (void *) &newkey);
if (ret < 0) { if (ret < 0) {
rte_exit(EXIT_FAILURE, "Unable to add entry %" PRIu32 rte_exit(EXIT_FAILURE, "Unable to add entry %" PRIu32
" to the l3fwd hash.\n", i); " to the l3fwd hash.\n", i);
} }
ipv4_l3fwd_out_if[ret] = entry.if_out; ipv4_l3fwd_out_if[ret] = entry->if_out;
ret = rte_eth_dev_info_get(em_route_base_v4[i].if_out,
&dev_info);
if (ret != 0)
rte_exit(EXIT_FAILURE,
"Error during getting device (port %u) info: %s\n",
em_route_base_v4[i].if_out, strerror(-ret));
src.s_addr = htonl(em_route_base_v4[i].v4_key.ip_src);
dst.s_addr = htonl(em_route_base_v4[i].v4_key.ip_dst);
printf("EM: Adding route %s, %s, %d, %d, %d (%d) [%s]\n",
inet_ntop(AF_INET, &dst, dstbuf, sizeof(dstbuf)),
inet_ntop(AF_INET, &src, srcbuf, sizeof(srcbuf)),
em_route_base_v4[i].v4_key.port_dst,
em_route_base_v4[i].v4_key.port_src,
em_route_base_v4[i].v4_key.proto,
em_route_base_v4[i].if_out, dev_info.device->name);
} }
printf("Hash: Adding 0x%" PRIx64 " keys\n", printf("Hash: Adding 0x%" PRIx64 " keys\n",
(uint64_t)IPV4_L3FWD_EM_NUM_ROUTES); (uint64_t)route_num_v4);
} }
#define BIT_16_TO_23 0x00ff0000 #define BIT_16_TO_23 0x00ff0000
static inline void static inline void
populate_ipv6_few_flow_into_table(const struct rte_hash *h) populate_ipv6_flow_into_table(const struct rte_hash *h)
{ {
uint32_t i; int i;
int32_t ret; int32_t ret;
struct rte_eth_dev_info dev_info;
char srcbuf[INET6_ADDRSTRLEN];
char dstbuf[INET6_ADDRSTRLEN];
mask1 = (rte_xmm_t){.u32 = {BIT_16_TO_23, ALL_32_BITS, mask1 = (rte_xmm_t){.u32 = {BIT_16_TO_23, ALL_32_BITS,
ALL_32_BITS, ALL_32_BITS} }; ALL_32_BITS, ALL_32_BITS} };
mask2 = (rte_xmm_t){.u32 = {ALL_32_BITS, ALL_32_BITS, 0, 0} }; mask2 = (rte_xmm_t){.u32 = {ALL_32_BITS, ALL_32_BITS, 0, 0} };
for (i = 0; i < IPV6_L3FWD_EM_NUM_ROUTES; i++) { for (i = 0; i < route_num_v6; i++) {
struct ipv6_l3fwd_em_route entry; struct em_rule *entry;
union ipv6_5tuple_host newkey; union ipv6_5tuple_host newkey;
entry = ipv6_l3fwd_em_route_array[i]; if ((1 << em_route_base_v6[i].if_out &
convert_ipv6_5tuple(&entry.key, &newkey); enabled_port_mask) == 0)
continue;
entry = &em_route_base_v6[i];
convert_ipv6_5tuple(&(entry->v6_key), &newkey);
ret = rte_hash_add_key(h, (void *) &newkey); ret = rte_hash_add_key(h, (void *) &newkey);
if (ret < 0) { if (ret < 0) {
rte_exit(EXIT_FAILURE, "Unable to add entry %" PRIu32 rte_exit(EXIT_FAILURE, "Unable to add entry %" PRIu32
" to the l3fwd hash.\n", i); " to the l3fwd hash.\n", i);
} }
ipv6_l3fwd_out_if[ret] = entry.if_out; ipv6_l3fwd_out_if[ret] = entry->if_out;
ret = rte_eth_dev_info_get(em_route_base_v6[i].if_out,
&dev_info);
if (ret != 0)
rte_exit(EXIT_FAILURE,
"Error during getting device (port %u) info: %s\n",
em_route_base_v6[i].if_out, strerror(-ret));
printf("EM: Adding route %s, %s, %d, %d, %d (%d) [%s]\n",
inet_ntop(AF_INET6, em_route_base_v6[i].v6_key.ip_dst,
dstbuf, sizeof(dstbuf)),
inet_ntop(AF_INET6, em_route_base_v6[i].v6_key.ip_src,
srcbuf, sizeof(srcbuf)),
em_route_base_v6[i].v6_key.port_dst,
em_route_base_v6[i].v6_key.port_src,
em_route_base_v6[i].v6_key.proto,
em_route_base_v6[i].if_out, dev_info.device->name);
} }
printf("Hash: Adding 0x%" PRIx64 "keys\n", printf("Hash: Adding 0x%" PRIx64 "keys\n",
(uint64_t)IPV6_L3FWD_EM_NUM_ROUTES); (uint64_t)route_num_v6);
}
#define NUMBER_PORT_USED 16
static inline void
populate_ipv4_many_flow_into_table(const struct rte_hash *h,
unsigned int nr_flow)
{
unsigned i;
mask0 = (rte_xmm_t){.u32 = {BIT_8_TO_15, ALL_32_BITS,
ALL_32_BITS, ALL_32_BITS} };
for (i = 0; i < nr_flow; i++) {
uint8_t port = i % NUMBER_PORT_USED;
struct ipv4_l3fwd_em_route entry;
union ipv4_5tuple_host newkey;
uint8_t a = (uint8_t)((port + 1) % BYTE_VALUE_MAX);
/* Create the ipv4 exact match flow */
memset(&entry, 0, sizeof(entry));
entry = ipv4_l3fwd_em_route_array[port];
entry.key.ip_dst = RTE_IPV4(198, 18, port, a);
convert_ipv4_5tuple(&entry.key, &newkey);
int32_t ret = rte_hash_add_key(h, (void *) &newkey);
if (ret < 0)
rte_exit(EXIT_FAILURE, "Unable to add entry %u\n", i);
ipv4_l3fwd_out_if[ret] = (uint8_t) entry.if_out;
}
printf("Hash: Adding 0x%x keys\n", nr_flow);
}
static inline void
populate_ipv6_many_flow_into_table(const struct rte_hash *h,
unsigned int nr_flow)
{
unsigned i;
mask1 = (rte_xmm_t){.u32 = {BIT_16_TO_23, ALL_32_BITS,
ALL_32_BITS, ALL_32_BITS} };
mask2 = (rte_xmm_t){.u32 = {ALL_32_BITS, ALL_32_BITS, 0, 0} };
for (i = 0; i < nr_flow; i++) {
uint8_t port = i % NUMBER_PORT_USED;
struct ipv6_l3fwd_em_route entry;
union ipv6_5tuple_host newkey;
/* Create the ipv6 exact match flow */
memset(&entry, 0, sizeof(entry));
entry = ipv6_l3fwd_em_route_array[port];
entry.key.ip_dst[15] = (port + 1) % BYTE_VALUE_MAX;
convert_ipv6_5tuple(&entry.key, &newkey);
int32_t ret = rte_hash_add_key(h, (void *) &newkey);
if (ret < 0)
rte_exit(EXIT_FAILURE, "Unable to add entry %u\n", i);
ipv6_l3fwd_out_if[ret] = (uint8_t) entry.if_out;
}
printf("Hash: Adding 0x%x keys\n", nr_flow);
} }
/* Requirements: /* Requirements:
@ -1017,35 +969,18 @@ setup_hash(const int socketid)
"Unable to create the l3fwd hash on socket %d\n", "Unable to create the l3fwd hash on socket %d\n",
socketid); socketid);
if (hash_entry_number != HASH_ENTRY_NUMBER_DEFAULT) { /*
/* For testing hash matching with a large number of flows we * Use data from ipv4/ipv6 l3fwd config file
* generate millions of IP 5-tuples with an incremented dst * directly to initialize the hash table.
* address to initialize the hash table. */ */
if (ipv6 == 0) { if (ipv6 == 0) {
/* populate the ipv4 hash */ /* populate the ipv4 hash */
populate_ipv4_many_flow_into_table( populate_ipv4_flow_into_table(
ipv4_l3fwd_em_lookup_struct[socketid], ipv4_l3fwd_em_lookup_struct[socketid]);
hash_entry_number);
} else {
/* populate the ipv6 hash */
populate_ipv6_many_flow_into_table(
ipv6_l3fwd_em_lookup_struct[socketid],
hash_entry_number);
}
} else { } else {
/* /* populate the ipv6 hash */
* Use data in ipv4/ipv6 l3fwd lookup table populate_ipv6_flow_into_table(
* directly to initialize the hash table. ipv6_l3fwd_em_lookup_struct[socketid]);
*/
if (ipv6 == 0) {
/* populate the ipv4 hash */
populate_ipv4_few_flow_into_table(
ipv4_l3fwd_em_lookup_struct[socketid]);
} else {
/* populate the ipv6 hash */
populate_ipv6_few_flow_into_table(
ipv6_l3fwd_em_lookup_struct[socketid]);
}
} }
} }
/* >8 End of initialization of hash parameters. */ /* >8 End of initialization of hash parameters. */

View File

@ -33,6 +33,22 @@ struct ipv6_l3fwd_route {
uint8_t if_out; uint8_t if_out;
}; };
struct ipv4_5tuple {
uint32_t ip_dst;
uint32_t ip_src;
uint16_t port_dst;
uint16_t port_src;
uint8_t proto;
} __rte_packed;
struct ipv6_5tuple {
uint8_t ip_dst[IPV6_ADDR_LEN];
uint8_t ip_src[IPV6_ADDR_LEN];
uint16_t port_dst;
uint16_t port_src;
uint8_t proto;
} __rte_packed;
struct lpm_route_rule { struct lpm_route_rule {
union { union {
uint32_t ip; uint32_t ip;
@ -45,15 +61,35 @@ struct lpm_route_rule {
uint8_t if_out; uint8_t if_out;
}; };
struct ipv4_l3fwd_em_route {
struct ipv4_5tuple key;
uint8_t if_out;
};
struct ipv6_l3fwd_em_route {
struct ipv6_5tuple key;
uint8_t if_out;
};
struct em_rule {
union {
struct ipv4_5tuple v4_key;
struct ipv6_5tuple v6_key;
};
uint8_t if_out;
};
extern struct lpm_route_rule *route_base_v4; extern struct lpm_route_rule *route_base_v4;
extern struct lpm_route_rule *route_base_v6; extern struct lpm_route_rule *route_base_v6;
extern int route_num_v4; extern int route_num_v4;
extern int route_num_v6; extern int route_num_v6;
extern const struct ipv4_l3fwd_route ipv4_l3fwd_route_array[16]; extern const struct ipv4_l3fwd_route ipv4_l3fwd_route_array[16];
extern const struct ipv6_l3fwd_route ipv6_l3fwd_route_array[16]; extern const struct ipv6_l3fwd_route ipv6_l3fwd_route_array[16];
extern const struct ipv4_l3fwd_em_route ipv4_l3fwd_em_route_array[16];
extern const struct ipv6_l3fwd_em_route ipv6_l3fwd_em_route_array[16];
void void
read_config_files_lpm(void); read_config_files_lpm(void);