From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 73A3EA04A4; Tue, 1 Mar 2022 15:50:27 +0100 (CET) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 9B58642706; Tue, 1 Mar 2022 15:50:18 +0100 (CET) Received: from mga05.intel.com (mga05.intel.com [192.55.52.43]) by mails.dpdk.org (Postfix) with ESMTP id 7BC694270B for ; Tue, 1 Mar 2022 15:50:16 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1646146216; x=1677682216; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=DbPrL3CwXuKgpfd7L6FbPC1d8BQ4kDR4b4odH2VFOmI=; b=idEZb19rsNTN1iQi9qQpi6jyjEtVLLL9xlT6iH8sAfeuQ6iS1RQ0M+R7 N3eZMHApqRMpEZZ7kX1o191N5hrkeXhq6fPlJTVPriR0pp2FnelvgADyI zyTPAzVEuNGkFOG+kWn6WVYOEJ79gjUMjGZZk2edno9LA76/rkOWMvrSX q6Ufv4GZ3OcwkvmKy5Wc64Xj9bajayujaDqUodAhNa6iLpTG1BFQKkfdz yTEYzlj3QBxdP6qfYAXEoiXuu9gcTHfE25Xa6vOg9zNhiNFtn8pawm1s8 0Cl+TIuSzJXRVBOJ4p0upf4waGHv6r1ozNb+jOQjtZ1pY2qkRP1T3ict/ Q==; X-IronPort-AV: E=McAfee;i="6200,9189,10272"; a="339576543" X-IronPort-AV: E=Sophos;i="5.90,146,1643702400"; d="scan'208";a="339576543" Received: from orsmga006.jf.intel.com ([10.7.209.51]) by fmsmga105.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 01 Mar 2022 06:50:15 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.90,146,1643702400"; d="scan'208";a="510535049" Received: from silpixa00401215.ir.intel.com ([10.55.128.96]) by orsmga006.jf.intel.com with ESMTP; 01 Mar 2022 06:50:14 -0800 From: Sean Morrissey To: Cc: dev@dpdk.org, Sean Morrissey , Konstantin Ananyev Subject: [PATCH v6 2/2] examples/l3fwd: add config file support for EM Date: Tue, 1 Mar 2022 14:49:08 +0000 Message-Id: <20220301144908.1449465-3-sean.morrissey@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220301144908.1449465-1-sean.morrissey@intel.com> References: <20220204195905.449192-1-sean.morrissey@intel.com> <20220301144908.1449465-1-sean.morrissey@intel.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org 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 relfect these changes. Signed-off-by: Sean Morrissey Acked-by: Konstantin Ananyev --- doc/guides/sample_app_ug/l3_forward.rst | 89 ++++++-- examples/l3fwd/em_default_v4.cfg | 17 ++ examples/l3fwd/em_default_v6.cfg | 17 ++ examples/l3fwd/em_route_parse.c | 266 +++++++++++++++++++++++- examples/l3fwd/l3fwd_em.c | 219 +++++++------------ examples/l3fwd/l3fwd_route.h | 38 +++- 6 files changed, 479 insertions(+), 167 deletions(-) create mode 100644 examples/l3fwd/em_default_v4.cfg create mode 100644 examples/l3fwd/em_default_v6.cfg diff --git a/doc/guides/sample_app_ug/l3_forward.rst b/doc/guides/sample_app_ug/l3_forward.rst index 6d7d7c5cc1..01d86db95d 100644 --- a/doc/guides/sample_app_ug/l3_forward.rst +++ b/doc/guides/sample_app_ug/l3_forward.rst @@ -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 - .//examples/dpdk-l3fwd -l 1,2 -n 4 -- -p 0x3 --config="(0,0,1),(1,0,2)" + .//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 - .//examples/dpdk-l3fwd -l 0-3 -n 4 -a -- -p 0x3 --eventq-sched=ordered + .//examples/dpdk-l3fwd -l 0-3 -n 4 -a -- -p 0x3 --eventq-sched=ordered --rule_ipv4="rule_ipv4.cfg" --rule_ipv6="rule_ipv6.cfg" or .. code-block:: console .//examples/dpdk-l3fwd -l 0-3 -n 4 -a \ - -- -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 - .//examples/dpdk-l3fwd -l 0-7 -s 0xf0000 -n 4 --vdev event_sw0 -- -p 0x3 --mode=eventdev --eventq-sched=ordered + .//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/ + +* A typical IPv4 EM rule line should have a format as shown below: + +R + +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 diff --git a/examples/l3fwd/em_default_v4.cfg b/examples/l3fwd/em_default_v4.cfg new file mode 100644 index 0000000000..b70bdb6601 --- /dev/null +++ b/examples/l3fwd/em_default_v4.cfg @@ -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 diff --git a/examples/l3fwd/em_default_v6.cfg b/examples/l3fwd/em_default_v6.cfg new file mode 100644 index 0000000000..0b94f8d8d2 --- /dev/null +++ b/examples/l3fwd/em_default_v6.cfg @@ -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 diff --git a/examples/l3fwd/em_route_parse.c b/examples/l3fwd/em_route_parse.c index 11d83d9b42..6c16832e94 100644 --- a/examples/l3fwd/em_route_parse.c +++ b/examples/l3fwd/em_route_parse.c @@ -2,17 +2,279 @@ * Copyright(c) 2022 Intel Corporation */ +#include +#include +#include +#include + +#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"); + } + } } diff --git a/examples/l3fwd/l3fwd_em.c b/examples/l3fwd/l3fwd_em.c index de5be9e0a4..24d0910fe0 100644 --- a/examples/l3fwd/l3fwd_em.c +++ b/examples/l3fwd/l3fwd_em.c @@ -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. */ diff --git a/examples/l3fwd/l3fwd_route.h b/examples/l3fwd/l3fwd_route.h index 63c0b4dde5..c244837745 100644 --- a/examples/l3fwd/l3fwd_route.h +++ b/examples/l3fwd/l3fwd_route.h @@ -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); -- 2.25.1