diff options
Diffstat (limited to 'examples/l4fwd/main.c')
-rw-r--r-- | examples/l4fwd/main.c | 313 |
1 files changed, 313 insertions, 0 deletions
diff --git a/examples/l4fwd/main.c b/examples/l4fwd/main.c new file mode 100644 index 0000000..37bd03e --- /dev/null +++ b/examples/l4fwd/main.c @@ -0,0 +1,313 @@ +/* + * Copyright (c) 2016 Intel Corporation. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <time.h> + +#include "netbe.h" +#include "parse.h" + +#define MAX_RULES 0x100 +#define MAX_TBL8 0x800 + +#define RX_RING_SIZE 0x400 +#define TX_RING_SIZE 0x800 + +#define MPOOL_CACHE_SIZE 0x100 +#define MPOOL_NB_BUF 0x20000 + +#define FRAG_MBUF_BUF_SIZE (RTE_PKTMBUF_HEADROOM + TLE_DST_MAX_HDR) +#define FRAG_TTL MS_PER_S +#define FRAG_TBL_BUCKET_ENTRIES 16 + +#define FIRST_PORT 0x8000 + +#define RX_CSUM_OFFLOAD (DEV_RX_OFFLOAD_IPV4_CKSUM | DEV_RX_OFFLOAD_UDP_CKSUM) +#define TX_CSUM_OFFLOAD (DEV_TX_OFFLOAD_IPV4_CKSUM | DEV_TX_OFFLOAD_UDP_CKSUM) + +RTE_DEFINE_PER_LCORE(struct netbe_lcore *, _be); +RTE_DEFINE_PER_LCORE(struct netfe_lcore *, _fe); + +#include "fwdtbl.h" + +/** + * Location to be modified to create the IPv4 hash key which helps + * to distribute packets based on the destination TCP/UDP port. + */ +#define RSS_HASH_KEY_DEST_PORT_LOC_IPV4 15 + +/** + * Location to be modified to create the IPv6 hash key which helps + * to distribute packets based on the destination TCP/UDP port. + */ +#define RSS_HASH_KEY_DEST_PORT_LOC_IPV6 39 + +/** + * Size of the rte_eth_rss_reta_entry64 array to update through + * rte_eth_dev_rss_reta_update. + */ +#define RSS_RETA_CONF_ARRAY_SIZE (ETH_RSS_RETA_SIZE_512/RTE_RETA_GROUP_SIZE) + +static volatile int force_quit; + +static struct netbe_cfg becfg; +static struct rte_mempool *mpool[RTE_MAX_NUMA_NODES + 1]; +static struct rte_mempool *frag_mpool[RTE_MAX_NUMA_NODES + 1]; +static char proto_name[3][10] = {"udp", "tcp", ""}; + +static const struct rte_eth_conf port_conf_default = { + .rxmode = { + .max_rx_pkt_len = ETHER_MAX_VLAN_FRAME_LEN, + .hw_vlan_strip = 1, + .jumbo_frame = 1, + }, +}; + +/* function pointers */ +static TLE_RX_BULK_FUNCTYPE tle_rx_bulk; +static TLE_TX_BULK_FUNCTYPE tle_tx_bulk; +static TLE_STREAM_RECV_FUNCTYPE tle_stream_recv; +static TLE_STREAM_CLOSE_FUNCTYPE tle_stream_close; + +static LCORE_MAIN_FUNCTYPE lcore_main; + +#include "common.h" +#include "parse.h" +#include "lcore.h" +#include "port.h" +#include "tcp.h" +#include "udp.h" + +int verbose = VERBOSE_NONE; + +static void +netbe_lcore_fini(struct netbe_cfg *cfg) +{ + uint32_t i; + + for (i = 0; i != cfg->cpu_num; i++) { + tle_ctx_destroy(cfg->cpu[i].ctx); + rte_ip_frag_table_destroy(cfg->cpu[i].ftbl); + rte_lpm_free(cfg->cpu[i].lpm4); + rte_lpm6_free(cfg->cpu[i].lpm6); + + rte_free(cfg->cpu[i].prtq); + cfg->cpu[i].prtq_num = 0; + } + + rte_free(cfg->cpu); + cfg->cpu_num = 0; + for (i = 0; i != cfg->prt_num; i++) { + rte_free(cfg->prt[i].lcore_id); + cfg->prt[i].nb_lcore = 0; + } + rte_free(cfg->prt); + cfg->prt_num = 0; +} + +static int +netbe_dest_init(const char *fname, struct netbe_cfg *cfg) +{ + int32_t rc; + uint32_t f, i, p; + uint32_t k, l, cnt; + struct netbe_lcore *lc; + struct netbe_dest_prm prm; + + rc = netbe_parse_dest(fname, &prm); + if (rc != 0) + return rc; + + rc = 0; + for (i = 0; i != prm.nb_dest; i++) { + + p = prm.dest[i].port; + f = prm.dest[i].family; + + cnt = 0; + for (k = 0; k != cfg->cpu_num; k++) { + lc = cfg->cpu + k; + for (l = 0; l != lc->prtq_num; l++) + if (lc->prtq[l].port.id == p) { + rc = netbe_add_dest(lc, l, f, + prm.dest + i, 1); + if (rc != 0) { + RTE_LOG(ERR, USER1, + "%s(lc=%u, family=%u) " + "could not add " + "destinations(%u)\n", + __func__, lc->id, f, i); + return -ENOSPC; + } + cnt++; + } + } + + if (cnt == 0) { + RTE_LOG(ERR, USER1, "%s(%s) error at line %u: " + "port %u not managed by any lcore;\n", + __func__, fname, prm.dest[i].line, p); + break; + } + } + + free(prm.dest); + return rc; +} + +static void +func_ptrs_init(uint32_t proto) { + if (proto == TLE_PROTO_TCP) { + tle_rx_bulk = tle_tcp_rx_bulk; + tle_tx_bulk = tle_tcp_tx_bulk; + tle_stream_recv = tle_tcp_stream_recv; + tle_stream_close = tle_tcp_stream_close; + + lcore_main = lcore_main_tcp; + + } else { + tle_rx_bulk = tle_udp_rx_bulk; + tle_tx_bulk = tle_udp_tx_bulk; + tle_stream_recv = tle_udp_stream_recv; + tle_stream_close = tle_udp_stream_close; + + lcore_main = lcore_main_udp; + } +} + +int +main(int argc, char *argv[]) +{ + int32_t rc; + uint32_t i; + struct tle_ctx_param ctx_prm; + struct netfe_lcore_prm feprm; + struct rte_eth_stats stats; + char fecfg_fname[PATH_MAX + 1]; + char becfg_fname[PATH_MAX + 1]; + struct lcore_prm prm[RTE_MAX_LCORE]; + struct rte_eth_dev_info dev_info; + + fecfg_fname[0] = 0; + becfg_fname[0] = 0; + memset(prm, 0, sizeof(prm)); + + rc = rte_eal_init(argc, argv); + if (rc < 0) + rte_exit(EXIT_FAILURE, + "%s: rte_eal_init failed with error code: %d\n", + __func__, rc); + + memset(&ctx_prm, 0, sizeof(ctx_prm)); + + signal(SIGINT, sig_handle); + + argc -= rc; + argv += rc; + + rc = parse_app_options(argc, argv, &becfg, &ctx_prm, + fecfg_fname, becfg_fname); + if (rc != 0) + rte_exit(EXIT_FAILURE, + "%s: parse_app_options failed with error code: %d\n", + __func__, rc); + + /* init all the function pointer */ + func_ptrs_init(becfg.proto); + + rc = netbe_port_init(&becfg); + if (rc != 0) + rte_exit(EXIT_FAILURE, + "%s: netbe_port_init failed with error code: %d\n", + __func__, rc); + + rc = netbe_lcore_init(&becfg, &ctx_prm); + if (rc != 0) + sig_handle(SIGQUIT); + + rc = netbe_dest_init(becfg_fname, &becfg); + if (rc != 0) + sig_handle(SIGQUIT); + + for (i = 0; i != becfg.prt_num && rc == 0; i++) { + RTE_LOG(NOTICE, USER1, "%s: starting port %u\n", + __func__, becfg.prt[i].id); + rc = rte_eth_dev_start(becfg.prt[i].id); + if (rc != 0) { + RTE_LOG(ERR, USER1, + "%s: rte_eth_dev_start(%u) returned " + "error code: %d\n", + __func__, becfg.prt[i].id, rc); + sig_handle(SIGQUIT); + } + rte_eth_dev_info_get(becfg.prt[i].id, &dev_info); + rc = update_rss_reta(&becfg.prt[i], &dev_info); + if (rc != 0) + sig_handle(SIGQUIT); + } + + feprm.max_streams = ctx_prm.max_streams * becfg.cpu_num; + + rc = (rc != 0) ? rc : netfe_parse_cfg(fecfg_fname, &feprm); + if (rc != 0) + sig_handle(SIGQUIT); + + for (i = 0; rc == 0 && i != becfg.cpu_num; i++) + prm[becfg.cpu[i].id].be.lc = becfg.cpu + i; + + rc = (rc != 0) ? rc : netfe_lcore_fill(prm, &feprm); + if (rc != 0) + sig_handle(SIGQUIT); + + /* launch all slave lcores. */ + RTE_LCORE_FOREACH_SLAVE(i) { + if (prm[i].be.lc != NULL || prm[i].fe.max_streams != 0) + rte_eal_remote_launch(lcore_main, prm + i, i); + } + + /* launch master lcore. */ + i = rte_get_master_lcore(); + if (prm[i].be.lc != NULL || prm[i].fe.max_streams != 0) + lcore_main(prm + i); + + rte_eal_mp_wait_lcore(); + + for (i = 0; i != becfg.prt_num; i++) { + RTE_LOG(NOTICE, USER1, "%s: stoping port %u\n", + __func__, becfg.prt[i].id); + rte_eth_stats_get(becfg.prt[i].id, &stats); + RTE_LOG(NOTICE, USER1, "port %u stats={\n" + "ipackets=%" PRIu64 ";" + "ibytes=%" PRIu64 ";" + "ierrors=%" PRIu64 ";" + "imissed=%" PRIu64 ";\n" + "opackets=%" PRIu64 ";" + "obytes=%" PRIu64 ";" + "oerrors=%" PRIu64 ";\n" + "}\n", + becfg.prt[i].id, + stats.ipackets, + stats.ibytes, + stats.ierrors, + stats.imissed, + stats.opackets, + stats.obytes, + stats.oerrors); + rte_eth_dev_stop(becfg.prt[i].id); + } + + netbe_lcore_fini(&becfg); + + return 0; +} |