From e18a033b921d0d79fa8278f853548e6125b93e0c Mon Sep 17 00:00:00 2001 From: Konstantin Ananyev Date: Tue, 31 Oct 2017 12:40:17 +0000 Subject: Integrate TLDK with NGINX Created a clone of nginx (from https://github.com/nginx/nginx) to demonstrate and benchmark TLDK library integrated with real world application. A new nginx module is created and and BSD socket-like API is implemented on top of native TLDK API. Note, that right now only minimalistic subset of socket-like API is provided: - accept - close - readv - recv - writev so only limited nginx functionality is available for a moment. Change-Id: Ie1efe9349a0538da4348a48fb8306cbf636b5a92 Signed-off-by: Mohammad Abdul Awal Signed-off-by: Reshma Pattan Signed-off-by: Remy Horton Signed-off-by: Konstantin Ananyev --- app/nginx/src/tldk/parse.c | 456 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 456 insertions(+) create mode 100644 app/nginx/src/tldk/parse.c (limited to 'app/nginx/src/tldk/parse.c') diff --git a/app/nginx/src/tldk/parse.c b/app/nginx/src/tldk/parse.c new file mode 100644 index 0000000..5d71d9e --- /dev/null +++ b/app/nginx/src/tldk/parse.c @@ -0,0 +1,456 @@ +/* + * Copyright (c) 2017 Intel Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +#include + +union parse_val { + uint64_t u64; + struct { + uint16_t family; + union { + struct in_addr addr4; + struct in6_addr addr6; + }; + } in; + struct ether_addr mac; + rte_cpuset_t cpuset; +}; + +struct key_handler { + const char *name; + int (*func)(const char *, void *); +}; + +static int +parse_uint_val(const char *val, void *prm) +{ + union parse_val *rv; + unsigned long v; + char *end; + + rv = prm; + errno = 0; + v = strtoul(val, &end, 0); + if (errno != 0 || end[0] != 0 || v > UINT32_MAX) + return -EINVAL; + + rv->u64 = v; + return 0; +} + +static int +parse_ipv4_val(const char *val, void *prm) +{ + union parse_val *rv; + + rv = prm; + if (inet_pton(AF_INET, val, &rv->in.addr4) != 1) + return -EINVAL; + rv->in.family = AF_INET; + return 0; +} + +static int +parse_ipv6_val(const char *val, void *prm) +{ + union parse_val *rv; + + rv = prm; + if (inet_pton(AF_INET6, val, &rv->in.addr6) != 1) + return -EINVAL; + rv->in.family = AF_INET6; + return 0; +} + +static int +parse_ip_val(const char *val, void *prm) +{ + if (parse_ipv6_val(val, prm) != 0 && + parse_ipv4_val(val, prm) != 0) + return -EINVAL; + return 0; +} + +#define PARSE_UINT8x16(s, v, l) \ +do { \ + char *end; \ + unsigned long t; \ + errno = 0; \ + t = strtoul((s), &end, 16); \ + if (errno != 0 || end[0] != (l) || t > UINT8_MAX) \ + return -EINVAL; \ + (s) = end + 1; \ + (v) = t; \ +} while (0) + +static int +parse_mac_val(const char *val, void *prm) +{ + union parse_val *rv; + const char *s; + + rv = prm; + s = val; + + PARSE_UINT8x16(s, rv->mac.addr_bytes[0], ':'); + PARSE_UINT8x16(s, rv->mac.addr_bytes[1], ':'); + PARSE_UINT8x16(s, rv->mac.addr_bytes[2], ':'); + PARSE_UINT8x16(s, rv->mac.addr_bytes[3], ':'); + PARSE_UINT8x16(s, rv->mac.addr_bytes[4], ':'); + PARSE_UINT8x16(s, rv->mac.addr_bytes[5], 0); + return 0; +} + +static char * +tldk_port_parse(ngx_conf_t *cf, struct tldk_port_conf *prt) +{ + uint32_t i, j; + ngx_str_t *v; + + static const struct key_handler kh[] = { + { + .name = "port", + .func = parse_uint_val, + }, + { + .name = "mtu", + .func = parse_uint_val, + }, + { + .name = "rx_offload", + .func = parse_uint_val, + }, + { + .name = "tx_offload", + .func = parse_uint_val, + }, + { + .name = "ipv4", + .func = parse_ipv4_val, + }, + { + .name = "ipv6", + .func = parse_ipv6_val, + }, + }; + + union parse_val pvl[RTE_DIM(kh)]; + + memset(pvl, 0, sizeof(pvl)); + pvl[1].u64 = ETHER_MAX_LEN - ETHER_CRC_LEN; + + if (cf->args->nelts % 2 != 0) + return NGX_CONF_ERROR; + + v = cf->args->elts; + for (i = 0; i != cf->args->nelts; i += 2) { + + for (j = 0; j != RTE_DIM(kh); j++) { + if (ngx_strcmp(v[i].data, kh[j].name) == 0) { + if (kh[j].func((const char *)v[i + 1].data, + pvl + j) < 0) + return NGX_CONF_ERROR; + else + break; + } + } + + /* unknow key */ + if (j == RTE_DIM(kh)) + return NGX_CONF_ERROR; + } + + memset(prt, 0, sizeof(*prt)); + + prt->id = pvl[0].u64; + prt->mtu = pvl[1].u64; + prt->rx_offload = pvl[2].u64; + prt->tx_offload = pvl[3].u64; + prt->ipv4 = pvl[4].in.addr4.s_addr; + prt->ipv6 = pvl[5].in.addr6; + + return NGX_CONF_OK; +} + +static char * +tldk_dev_parse(ngx_conf_t *cf, struct tldk_dev_conf *dev, + tldk_conf_t *tcf) +{ + uint32_t i, j; + ngx_str_t *v; + + static const struct key_handler kh[] = { + { + .name = "dev", + .func = parse_uint_val, + }, + { + .name = "port", + .func = parse_uint_val, + }, + { + .name = "queue", + .func = parse_uint_val, + }, + }; + + union parse_val pvl[RTE_DIM(kh)]; + + memset(pvl, 0, sizeof(pvl)); + + if (cf->args->nelts % 2 != 0) + return NGX_CONF_ERROR; + + v = cf->args->elts; + for (i = 0; i != cf->args->nelts; i += 2) { + + for (j = 0; j != RTE_DIM(kh); j++) { + if (ngx_strcmp(v[i].data, kh[j].name) == 0) { + if (kh[j].func((const char *)v[i + 1].data, + pvl + j) < 0) + return NGX_CONF_ERROR; + else + break; + } + } + + /* unknow key */ + if (j == RTE_DIM(kh)) + return NGX_CONF_ERROR; + } + + memset(dev, 0, sizeof(*dev)); + + dev->id = pvl[0].u64; + dev->port = pvl[1].u64; + dev->queue = pvl[2].u64; + + return NGX_CONF_OK; +} + +static char * +tldk_dest_parse(ngx_conf_t *cf, struct tldk_dest_conf *dst) +{ + uint32_t i, j; + ngx_str_t *v; + + static const struct key_handler kh[] = { + { + .name = "dev", + .func = parse_uint_val, + }, + { + .name = "mtu", + .func = parse_uint_val, + }, + { + .name = "masklen", + .func = parse_uint_val, + }, + { + .name = "addr", + .func = parse_ip_val, + }, + { + .name = "mac", + .func = parse_mac_val, + }, + }; + + union parse_val pvl[RTE_DIM(kh)]; + + memset(pvl, 0, sizeof(pvl)); + pvl[1].u64 = ETHER_MAX_LEN - ETHER_CRC_LEN; + + if (cf->args->nelts % 2 != 1 || cf->args->nelts == 1) + return NGX_CONF_ERROR; + + v = cf->args->elts; + for (i = 1; i != cf->args->nelts; i += 2) { + + for (j = 0; j != RTE_DIM(kh); j++) { + if (ngx_strcmp(v[i].data, kh[j].name) == 0) { + if (kh[j].func((const char *)v[i + 1].data, + pvl + j) < 0) + return NGX_CONF_ERROR; + else + break; + } + } + + /* unknow key */ + if (j == RTE_DIM(kh)) + return NGX_CONF_ERROR; + } + + memset(dst, 0, sizeof(*dst)); + + dst->dev = pvl[0].u64; + dst->mtu = pvl[1].u64; + dst->prfx = pvl[2].u64; + + dst->family = pvl[3].in.family; + if (pvl[3].in.family == AF_INET) + dst->ipv4 = pvl[3].in.addr4; + else + dst->ipv6 = pvl[3].in.addr6; + + memcpy(&dst->mac, &pvl[4].mac, sizeof(dst->mac)); + + return NGX_CONF_OK; +} + +char * +tldk_block_parse(ngx_conf_t *cf, ngx_command_t *dummy, void *conf) +{ + uint32_t i, len, n; + tldk_conf_t *tcf; + ngx_str_t *v; + char *rv, *s; + struct tldk_port_conf prt; + + tcf = (tldk_conf_t *)((void **)conf)[0]; + v = cf->args->elts; + + if (ngx_strcmp(v[0].data, "eal_cmd") == 0) { + + if (cf->args->nelts == 1 || + cf->args->nelts > RTE_DIM(tcf->eal_argv)) + return NGX_CONF_ERROR; + + s = tcf->eal_cmd; + len = sizeof(tcf->eal_cmd); + for (i = 0; i != cf->args->nelts; i++) { + n = snprintf(s, len, "%s", v[i].data) + 1; + if (n > len) + return NGX_CONF_ERROR; + tcf->eal_argv[i] = s; + s += n; + len -= n; + } + + tcf->eal_argc = i; + return NGX_CONF_OK; + + } else if (ngx_strcmp(v[0].data, "port") == 0) { + + rv = tldk_port_parse(cf, &prt); + if (rv == NGX_CONF_OK) { + + /* too many ports */ + if (tcf->nb_port >= RTE_DIM(tcf->port)) + return NGX_CONF_ERROR; + + /* copy stuff */ + tcf->port[tcf->nb_port++] = prt; + } + return rv; + } + + return NGX_CONF_ERROR; +} + +char * +tldk_ctx_parse(ngx_conf_t *cf, ngx_command_t *dummy, void *conf) +{ + char *rv; + ngx_str_t *v; + tldk_conf_t *tcf; + struct tldk_ctx_conf *tcx; + union parse_val pvl; + + tcf = (tldk_conf_t *)((void **)conf)[0]; + tcx = tcf->ctx + tcf->nb_ctx; + v = cf->args->elts; + + if (ngx_strcmp(v[0].data, "worker") == 0) { + if (cf->args->nelts != 2 || + parse_uint_val((const char *)v[1].data, + &pvl) < 0) + return NGX_CONF_ERROR; + tcx->worker = pvl.u64; + } else if (ngx_strcmp(v[0].data, "lcore") == 0) { + if (cf->args->nelts != 2 || + parse_uint_val((const char *)v[1].data, + &pvl) < 0) + return NGX_CONF_ERROR; + tcx->lcore = pvl.u64; + } else if (ngx_strcmp(v[0].data, "mbufs") == 0) { + if (cf->args->nelts != 2 || + parse_uint_val((const char *)v[1].data, + &pvl) < 0) + return NGX_CONF_ERROR; + tcx->nb_mbuf = pvl.u64; + } else if (ngx_strcmp(v[0].data, "streams") == 0) { + if (cf->args->nelts != 2 || + parse_uint_val((const char *)v[1].data, + &pvl) < 0) + return NGX_CONF_ERROR; + tcx->nb_stream = pvl.u64; + } else if (ngx_strcmp(v[0].data, "rbufs") == 0) { + if (cf->args->nelts != 2 || + parse_uint_val((const char *)v[1].data, + &pvl) < 0) + return NGX_CONF_ERROR; + tcx->nb_rbuf = pvl.u64; + } else if (ngx_strcmp(v[0].data, "sbufs") == 0) { + if (cf->args->nelts != 2 || + parse_uint_val((const char *)v[1].data, + &pvl) < 0) + return NGX_CONF_ERROR; + tcx->nb_sbuf = pvl.u64; + } else if (ngx_strcmp(v[0].data, "be_in_worker") == 0) { + if (cf->args->nelts != 1) + return NGX_CONF_ERROR; + tcx->be_in_worker = 1; + } else if (ngx_strcmp(v[0].data, "tcp_timewait") == 0) { + if (cf->args->nelts != 2 || + parse_uint_val((const char *)v[1].data, + &pvl) < 0) + return NGX_CONF_ERROR; + tcx->tcp_timewait = pvl.u64; + } else if (ngx_strcmp(v[0].data, "dev") == 0) { + if (tcx->nb_dev >= RTE_DIM(tcx->dev)) + return NGX_CONF_ERROR; + rv = tldk_dev_parse(cf, tcx->dev + tcx->nb_dev, tcf); + if (rv != NGX_CONF_OK) + return rv; + tcx->nb_dev++; + return rv; + } else if (ngx_strcmp(v[0].data, "dest") == 0) { + if (tcx->nb_dest >= RTE_DIM(tcx->dest)) + return NGX_CONF_ERROR; + rv = tldk_dest_parse(cf, tcx->dest + tcx->nb_dest); + if (rv != NGX_CONF_OK) + return rv; + tcx->nb_dest++; + } + + return NGX_CONF_OK; +} -- cgit 1.2.3-korg