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:
parent
52def963fc
commit
e7e6dd6430
@ -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
|
||||
both IPv4 and IPv6.
|
||||
LPM-based forwarding supports IPv4 only.
|
||||
During the initialization phase route rules for IPv4 and IPv6 are read from rule files.
|
||||
|
||||
Compiling the Application
|
||||
-------------------------
|
||||
@ -61,6 +62,8 @@ Running the Application
|
||||
The application has a number of command line options::
|
||||
|
||||
./dpdk-l3fwd [EAL options] -- -p PORTMASK
|
||||
--rule_ipv4=FILE
|
||||
--rule_ipv6=FILE
|
||||
[-P]
|
||||
[--lookup LOOKUP_METHOD]
|
||||
--config(port,queue,lcore)[,(port,queue,lcore)]
|
||||
@ -82,6 +85,11 @@ Where,
|
||||
|
||||
* ``-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.
|
||||
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
|
||||
|
||||
./<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:
|
||||
|
||||
@ -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,
|
||||
Following is the sample command:
|
||||
|
||||
.. 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
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
./<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:
|
||||
|
||||
@ -192,7 +204,7 @@ scheduler. Following is the sample command:
|
||||
|
||||
.. 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
|
||||
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 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
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@ -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,
|
||||
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::
|
||||
|
||||
@ -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) {
|
||||
/* populate the ipv4 hash */
|
||||
populate_ipv4_many_flow_into_table(ipv4_l3fwd_lookup_struct[socketid], hash_entry_number);
|
||||
} else {
|
||||
/* populate the ipv6 hash */
|
||||
populate_ipv6_many_flow_into_table( ipv6_l3fwd_lookup_struct[socketid], hash_entry_number);
|
||||
}
|
||||
} 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]);
|
||||
}
|
||||
if (ipv6 == 0) {
|
||||
/* populate the ipv4 hash */
|
||||
populate_ipv4_flow_into_table(
|
||||
ipv4_l3fwd_em_lookup_struct[socketid]);
|
||||
} else {
|
||||
/* populate the ipv6 hash */
|
||||
populate_ipv6_flow_into_table(
|
||||
ipv6_l3fwd_em_lookup_struct[socketid]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
17
examples/l3fwd/em_default_v4.cfg
Normal file
17
examples/l3fwd/em_default_v4.cfg
Normal 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
|
17
examples/l3fwd/em_default_v6.cfg
Normal file
17
examples/l3fwd/em_default_v6.cfg
Normal 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
|
@ -2,17 +2,279 @@
|
||||
* 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"
|
||||
|
||||
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
|
||||
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 */
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -43,14 +43,6 @@
|
||||
|
||||
#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 {
|
||||
struct {
|
||||
uint8_t pad0;
|
||||
@ -66,14 +58,6 @@ union ipv4_5tuple_host {
|
||||
|
||||
#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 {
|
||||
struct {
|
||||
uint16_t pad0;
|
||||
@ -88,22 +72,10 @@ union ipv6_5tuple_host {
|
||||
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).
|
||||
* 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, 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},
|
||||
@ -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).
|
||||
* 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, 1}, 9, 9, IPPROTO_UDP}, 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;
|
||||
}
|
||||
|
||||
#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 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
|
||||
|
||||
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;
|
||||
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,
|
||||
ALL_32_BITS, ALL_32_BITS} };
|
||||
|
||||
for (i = 0; i < IPV4_L3FWD_EM_NUM_ROUTES; i++) {
|
||||
struct ipv4_l3fwd_em_route entry;
|
||||
for (i = 0; i < route_num_v4; i++) {
|
||||
struct em_rule *entry;
|
||||
union ipv4_5tuple_host newkey;
|
||||
struct in_addr src;
|
||||
struct in_addr dst;
|
||||
|
||||
entry = ipv4_l3fwd_em_route_array[i];
|
||||
convert_ipv4_5tuple(&entry.key, &newkey);
|
||||
if ((1 << em_route_base_v4[i].if_out &
|
||||
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);
|
||||
if (ret < 0) {
|
||||
rte_exit(EXIT_FAILURE, "Unable to add entry %" PRIu32
|
||||
" 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",
|
||||
(uint64_t)IPV4_L3FWD_EM_NUM_ROUTES);
|
||||
(uint64_t)route_num_v4);
|
||||
}
|
||||
|
||||
#define BIT_16_TO_23 0x00ff0000
|
||||
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;
|
||||
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,
|
||||
ALL_32_BITS, ALL_32_BITS} };
|
||||
|
||||
mask2 = (rte_xmm_t){.u32 = {ALL_32_BITS, ALL_32_BITS, 0, 0} };
|
||||
|
||||
for (i = 0; i < IPV6_L3FWD_EM_NUM_ROUTES; i++) {
|
||||
struct ipv6_l3fwd_em_route entry;
|
||||
for (i = 0; i < route_num_v6; i++) {
|
||||
struct em_rule *entry;
|
||||
union ipv6_5tuple_host newkey;
|
||||
|
||||
entry = ipv6_l3fwd_em_route_array[i];
|
||||
convert_ipv6_5tuple(&entry.key, &newkey);
|
||||
if ((1 << em_route_base_v6[i].if_out &
|
||||
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);
|
||||
if (ret < 0) {
|
||||
rte_exit(EXIT_FAILURE, "Unable to add entry %" PRIu32
|
||||
" 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",
|
||||
(uint64_t)IPV6_L3FWD_EM_NUM_ROUTES);
|
||||
}
|
||||
|
||||
#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);
|
||||
(uint64_t)route_num_v6);
|
||||
}
|
||||
|
||||
/* Requirements:
|
||||
@ -1017,35 +969,18 @@ setup_hash(const int socketid)
|
||||
"Unable to create the l3fwd hash on socket %d\n",
|
||||
socketid);
|
||||
|
||||
if (hash_entry_number != HASH_ENTRY_NUMBER_DEFAULT) {
|
||||
/* For testing hash matching with a large number of flows we
|
||||
* generate millions of IP 5-tuples with an incremented dst
|
||||
* address to initialize the hash table. */
|
||||
if (ipv6 == 0) {
|
||||
/* populate the ipv4 hash */
|
||||
populate_ipv4_many_flow_into_table(
|
||||
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);
|
||||
}
|
||||
/*
|
||||
* Use data from ipv4/ipv6 l3fwd config file
|
||||
* directly to initialize the hash table.
|
||||
*/
|
||||
if (ipv6 == 0) {
|
||||
/* populate the ipv4 hash */
|
||||
populate_ipv4_flow_into_table(
|
||||
ipv4_l3fwd_em_lookup_struct[socketid]);
|
||||
} else {
|
||||
/*
|
||||
* Use data in ipv4/ipv6 l3fwd lookup table
|
||||
* directly to initialize the hash table.
|
||||
*/
|
||||
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]);
|
||||
}
|
||||
/* populate the ipv6 hash */
|
||||
populate_ipv6_flow_into_table(
|
||||
ipv6_l3fwd_em_lookup_struct[socketid]);
|
||||
}
|
||||
}
|
||||
/* >8 End of initialization of hash parameters. */
|
||||
|
@ -33,6 +33,22 @@ struct ipv6_l3fwd_route {
|
||||
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 {
|
||||
union {
|
||||
uint32_t ip;
|
||||
@ -45,15 +61,35 @@ struct lpm_route_rule {
|
||||
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_v6;
|
||||
extern int route_num_v4;
|
||||
extern int route_num_v6;
|
||||
|
||||
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 ipv4_l3fwd_em_route ipv4_l3fwd_em_route_array[16];
|
||||
extern const struct ipv6_l3fwd_em_route ipv6_l3fwd_em_route_array[16];
|
||||
|
||||
void
|
||||
read_config_files_lpm(void);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user