dpdk/examples/ipsec-secgw/parser.c
<<
>>
Prefs
   1/* SPDX-License-Identifier: BSD-3-Clause
   2 * Copyright(c) 2016 Intel Corporation
   3 */
   4#include <stdlib.h>
   5#include <arpa/inet.h>
   6#include <sys/socket.h>
   7
   8#include <rte_common.h>
   9#include <rte_crypto.h>
  10#include <rte_string_fns.h>
  11
  12#include <cmdline_parse_string.h>
  13#include <cmdline_parse_num.h>
  14#include <cmdline_parse_ipaddr.h>
  15#include <cmdline_socket.h>
  16#include <cmdline.h>
  17
  18#include "flow.h"
  19#include "ipsec.h"
  20#include "parser.h"
  21
  22#define PARSE_DELIMITER         " \f\n\r\t\v"
  23static int
  24parse_tokenize_string(char *string, char *tokens[], uint32_t *n_tokens)
  25{
  26        uint32_t i;
  27
  28        if ((string == NULL) ||
  29                (tokens == NULL) ||
  30                (*n_tokens < 1))
  31                return -EINVAL;
  32
  33        for (i = 0; i < *n_tokens; i++) {
  34                tokens[i] = strtok_r(string, PARSE_DELIMITER, &string);
  35                if (tokens[i] == NULL)
  36                        break;
  37        }
  38
  39        if ((i == *n_tokens) &&
  40                (NULL != strtok_r(string, PARSE_DELIMITER, &string)))
  41                return -E2BIG;
  42
  43        *n_tokens = i;
  44        return 0;
  45}
  46
  47int
  48parse_ipv4_addr(const char *token, struct in_addr *ipv4, uint32_t *mask)
  49{
  50        char ip_str[INET_ADDRSTRLEN] = {0};
  51        char *pch;
  52
  53        pch = strchr(token, '/');
  54        if (pch != NULL) {
  55                strlcpy(ip_str, token,
  56                        RTE_MIN((unsigned int long)(pch - token + 1),
  57                        sizeof(ip_str)));
  58                pch += 1;
  59                if (is_str_num(pch) != 0)
  60                        return -EINVAL;
  61                if (mask)
  62                        *mask = atoi(pch);
  63        } else {
  64                strlcpy(ip_str, token, sizeof(ip_str));
  65                if (mask)
  66                        *mask = 0;
  67        }
  68        if (strlen(ip_str) >= INET_ADDRSTRLEN)
  69                return -EINVAL;
  70
  71        if (inet_pton(AF_INET, ip_str, ipv4) != 1)
  72                return -EINVAL;
  73
  74        return 0;
  75}
  76
  77int
  78parse_ipv6_addr(const char *token, struct in6_addr *ipv6, uint32_t *mask)
  79{
  80        char ip_str[256] = {0};
  81        char *pch;
  82
  83        pch = strchr(token, '/');
  84        if (pch != NULL) {
  85                strlcpy(ip_str, token,
  86                        RTE_MIN((unsigned int long)(pch - token + 1),
  87                                        sizeof(ip_str)));
  88                pch += 1;
  89                if (is_str_num(pch) != 0)
  90                        return -EINVAL;
  91                if (mask)
  92                        *mask = atoi(pch);
  93        } else {
  94                strlcpy(ip_str, token, sizeof(ip_str));
  95                if (mask)
  96                        *mask = 0;
  97        }
  98
  99        if (strlen(ip_str) >= INET6_ADDRSTRLEN)
 100                return -EINVAL;
 101
 102        if (inet_pton(AF_INET6, ip_str, ipv6) != 1)
 103                return -EINVAL;
 104
 105        return 0;
 106}
 107
 108int
 109parse_range(const char *token, uint16_t *low, uint16_t *high)
 110{
 111        char ch;
 112        char num_str[20];
 113        uint32_t pos;
 114        int range_low = -1;
 115        int range_high = -1;
 116
 117        if (!low || !high)
 118                return -1;
 119
 120        memset(num_str, 0, 20);
 121        pos = 0;
 122
 123        while ((ch = *token++) != '\0') {
 124                if (isdigit(ch)) {
 125                        if (pos >= 19)
 126                                return -1;
 127                        num_str[pos++] = ch;
 128                } else if (ch == ':') {
 129                        if (range_low != -1)
 130                                return -1;
 131                        range_low = atoi(num_str);
 132                        memset(num_str, 0, 20);
 133                        pos = 0;
 134                }
 135        }
 136
 137        if (strlen(num_str) == 0)
 138                return -1;
 139
 140        range_high = atoi(num_str);
 141
 142        *low = (uint16_t)range_low;
 143        *high = (uint16_t)range_high;
 144
 145        return 0;
 146}
 147
 148/*
 149 * helper function for parse_mac, parse one section of the ether addr.
 150 */
 151static const char *
 152parse_uint8x16(const char *s, uint8_t *v, uint8_t ls)
 153{
 154        char *end;
 155        unsigned long t;
 156
 157        errno = 0;
 158        t = strtoul(s, &end, 16);
 159        if (errno != 0 || end[0] != ls || t > UINT8_MAX)
 160                return NULL;
 161        v[0] = t;
 162        return end + 1;
 163}
 164
 165static int
 166parse_mac(const char *str, struct rte_ether_addr *addr)
 167{
 168        uint32_t i;
 169
 170        static const uint8_t stop_sym[RTE_DIM(addr->addr_bytes)] = {
 171                [0] = ':',
 172                [1] = ':',
 173                [2] = ':',
 174                [3] = ':',
 175                [4] = ':',
 176                [5] = 0,
 177        };
 178
 179        for (i = 0; i != RTE_DIM(addr->addr_bytes); i++) {
 180                str = parse_uint8x16(str, addr->addr_bytes + i, stop_sym[i]);
 181                if (str == NULL)
 182                        return -EINVAL;
 183        }
 184
 185        return 0;
 186}
 187
 188/** sp add parse */
 189struct cfg_sp_add_cfg_item {
 190        cmdline_fixed_string_t sp_keyword;
 191        cmdline_multi_string_t multi_string;
 192};
 193
 194static void
 195cfg_sp_add_cfg_item_parsed(void *parsed_result,
 196        __rte_unused struct cmdline *cl, void *data)
 197{
 198        struct cfg_sp_add_cfg_item *params = parsed_result;
 199        char *tokens[32];
 200        uint32_t n_tokens = RTE_DIM(tokens);
 201        struct parse_status *status = (struct parse_status *)data;
 202
 203        APP_CHECK((parse_tokenize_string(params->multi_string, tokens,
 204                &n_tokens) == 0), status, "too many arguments");
 205
 206        if (status->status < 0)
 207                return;
 208
 209        if (strcmp(tokens[0], "ipv4") == 0) {
 210                parse_sp4_tokens(tokens, n_tokens, status);
 211                if (status->status < 0)
 212                        return;
 213        } else if (strcmp(tokens[0], "ipv6") == 0) {
 214                parse_sp6_tokens(tokens, n_tokens, status);
 215                if (status->status < 0)
 216                        return;
 217        } else {
 218                APP_CHECK(0, status, "unrecognizable input %s\n",
 219                        tokens[0]);
 220                return;
 221        }
 222}
 223
 224static cmdline_parse_token_string_t cfg_sp_add_sp_str =
 225        TOKEN_STRING_INITIALIZER(struct cfg_sp_add_cfg_item,
 226                sp_keyword, "sp");
 227
 228static cmdline_parse_token_string_t cfg_sp_add_multi_str =
 229        TOKEN_STRING_INITIALIZER(struct cfg_sp_add_cfg_item, multi_string,
 230                TOKEN_STRING_MULTI);
 231
 232cmdline_parse_inst_t cfg_sp_add_rule = {
 233        .f = cfg_sp_add_cfg_item_parsed,
 234        .data = NULL,
 235        .help_str = "",
 236        .tokens = {
 237                (void *) &cfg_sp_add_sp_str,
 238                (void *) &cfg_sp_add_multi_str,
 239                NULL,
 240        },
 241};
 242
 243/* sa add parse */
 244struct cfg_sa_add_cfg_item {
 245        cmdline_fixed_string_t sa_keyword;
 246        cmdline_multi_string_t multi_string;
 247};
 248
 249static void
 250cfg_sa_add_cfg_item_parsed(void *parsed_result,
 251        __rte_unused struct cmdline *cl, void *data)
 252{
 253        struct cfg_sa_add_cfg_item *params = parsed_result;
 254        char *tokens[32];
 255        uint32_t n_tokens = RTE_DIM(tokens);
 256        struct parse_status *status = (struct parse_status *)data;
 257
 258        APP_CHECK(parse_tokenize_string(params->multi_string, tokens,
 259                &n_tokens) == 0, status, "too many arguments\n");
 260
 261        parse_sa_tokens(tokens, n_tokens, status);
 262}
 263
 264static cmdline_parse_token_string_t cfg_sa_add_sa_str =
 265        TOKEN_STRING_INITIALIZER(struct cfg_sa_add_cfg_item,
 266                sa_keyword, "sa");
 267
 268static cmdline_parse_token_string_t cfg_sa_add_multi_str =
 269        TOKEN_STRING_INITIALIZER(struct cfg_sa_add_cfg_item, multi_string,
 270                TOKEN_STRING_MULTI);
 271
 272cmdline_parse_inst_t cfg_sa_add_rule = {
 273        .f = cfg_sa_add_cfg_item_parsed,
 274        .data = NULL,
 275        .help_str = "",
 276        .tokens = {
 277                (void *) &cfg_sa_add_sa_str,
 278                (void *) &cfg_sa_add_multi_str,
 279                NULL,
 280        },
 281};
 282
 283/* rt add parse */
 284struct cfg_rt_add_cfg_item {
 285        cmdline_fixed_string_t rt_keyword;
 286        cmdline_multi_string_t multi_string;
 287};
 288
 289static void
 290cfg_rt_add_cfg_item_parsed(void *parsed_result,
 291        __rte_unused struct cmdline *cl, void *data)
 292{
 293        struct cfg_rt_add_cfg_item *params = parsed_result;
 294        char *tokens[32];
 295        uint32_t n_tokens = RTE_DIM(tokens);
 296        struct parse_status *status = (struct parse_status *)data;
 297
 298        APP_CHECK(parse_tokenize_string(
 299                params->multi_string, tokens, &n_tokens) == 0,
 300                status, "too many arguments\n");
 301        if (status->status < 0)
 302                return;
 303
 304        parse_rt_tokens(tokens, n_tokens, status);
 305}
 306
 307static cmdline_parse_token_string_t cfg_rt_add_rt_str =
 308        TOKEN_STRING_INITIALIZER(struct cfg_rt_add_cfg_item,
 309                rt_keyword, "rt");
 310
 311static cmdline_parse_token_string_t cfg_rt_add_multi_str =
 312        TOKEN_STRING_INITIALIZER(struct cfg_rt_add_cfg_item, multi_string,
 313                TOKEN_STRING_MULTI);
 314
 315cmdline_parse_inst_t cfg_rt_add_rule = {
 316        .f = cfg_rt_add_cfg_item_parsed,
 317        .data = NULL,
 318        .help_str = "",
 319        .tokens = {
 320                (void *) &cfg_rt_add_rt_str,
 321                (void *) &cfg_rt_add_multi_str,
 322                NULL,
 323        },
 324};
 325
 326/* flow add parse */
 327struct cfg_flow_add_cfg_item {
 328        cmdline_fixed_string_t flow_keyword;
 329        cmdline_multi_string_t multi_string;
 330};
 331
 332static void
 333cfg_flow_add_cfg_item_parsed(void *parsed_result,
 334        __rte_unused struct cmdline *cl, void *data)
 335{
 336        struct cfg_flow_add_cfg_item *params = parsed_result;
 337        char *tokens[32];
 338        uint32_t n_tokens = RTE_DIM(tokens);
 339        struct parse_status *status = (struct parse_status *)data;
 340
 341        APP_CHECK(parse_tokenize_string(
 342                params->multi_string, tokens, &n_tokens) == 0,
 343                status, "too many arguments\n");
 344        if (status->status < 0)
 345                return;
 346
 347        parse_flow_tokens(tokens, n_tokens, status);
 348}
 349
 350static cmdline_parse_token_string_t cfg_flow_add_flow_str =
 351        TOKEN_STRING_INITIALIZER(struct cfg_flow_add_cfg_item,
 352                flow_keyword, "flow");
 353
 354static cmdline_parse_token_string_t cfg_flow_add_multi_str =
 355        TOKEN_STRING_INITIALIZER(struct cfg_flow_add_cfg_item, multi_string,
 356                TOKEN_STRING_MULTI);
 357
 358cmdline_parse_inst_t cfg_flow_add_rule = {
 359        .f = cfg_flow_add_cfg_item_parsed,
 360        .data = NULL,
 361        .help_str = "",
 362        .tokens = {
 363                (void *) &cfg_flow_add_flow_str,
 364                (void *) &cfg_flow_add_multi_str,
 365                NULL,
 366        },
 367};
 368
 369/* neigh add parse */
 370struct cfg_neigh_add_item {
 371        cmdline_fixed_string_t neigh;
 372        cmdline_fixed_string_t pstr;
 373        uint16_t port;
 374        cmdline_fixed_string_t mac;
 375};
 376
 377static void
 378cfg_parse_neigh(void *parsed_result, __rte_unused struct cmdline *cl,
 379        void *data)
 380{
 381        int32_t rc;
 382        struct cfg_neigh_add_item *res;
 383        struct parse_status *st;
 384        struct rte_ether_addr mac;
 385
 386        st = data;
 387        res = parsed_result;
 388        rc = parse_mac(res->mac, &mac);
 389        APP_CHECK(rc == 0, st, "invalid ether addr:%s", res->mac);
 390        rc = add_dst_ethaddr(res->port, &mac);
 391        APP_CHECK(rc == 0, st, "invalid port numer:%hu", res->port);
 392        if (st->status < 0)
 393                return;
 394}
 395
 396cmdline_parse_token_string_t cfg_add_neigh_start =
 397        TOKEN_STRING_INITIALIZER(struct cfg_neigh_add_item, neigh, "neigh");
 398cmdline_parse_token_string_t cfg_add_neigh_pstr =
 399        TOKEN_STRING_INITIALIZER(struct cfg_neigh_add_item, pstr, "port");
 400cmdline_parse_token_num_t cfg_add_neigh_port =
 401        TOKEN_NUM_INITIALIZER(struct cfg_neigh_add_item, port, RTE_UINT16);
 402cmdline_parse_token_string_t cfg_add_neigh_mac =
 403        TOKEN_STRING_INITIALIZER(struct cfg_neigh_add_item, mac, NULL);
 404
 405cmdline_parse_inst_t cfg_neigh_add_rule = {
 406        .f = cfg_parse_neigh,
 407        .data = NULL,
 408        .help_str = "",
 409        .tokens = {
 410                (void *)&cfg_add_neigh_start,
 411                (void *)&cfg_add_neigh_pstr,
 412                (void *)&cfg_add_neigh_port,
 413                (void *)&cfg_add_neigh_mac,
 414                NULL,
 415        },
 416};
 417
 418/** set of cfg items */
 419cmdline_parse_ctx_t ipsec_ctx[] = {
 420        (cmdline_parse_inst_t *)&cfg_sp_add_rule,
 421        (cmdline_parse_inst_t *)&cfg_sa_add_rule,
 422        (cmdline_parse_inst_t *)&cfg_rt_add_rule,
 423        (cmdline_parse_inst_t *)&cfg_flow_add_rule,
 424        (cmdline_parse_inst_t *)&cfg_neigh_add_rule,
 425        NULL,
 426};
 427
 428int
 429parse_cfg_file(const char *cfg_filename)
 430{
 431        struct cmdline *cl = cmdline_stdin_new(ipsec_ctx, "");
 432        FILE *f = fopen(cfg_filename, "r");
 433        char str[1024] = {0}, *get_s = NULL;
 434        uint32_t line_num = 0;
 435        struct parse_status status = {0};
 436
 437        if (f == NULL) {
 438                rte_panic("Error: invalid file descriptor %s\n", cfg_filename);
 439                goto error_exit;
 440        }
 441
 442        if (cl == NULL) {
 443                rte_panic("Error: cannot create cmdline instance\n");
 444                goto error_exit;
 445        }
 446
 447        cfg_sp_add_rule.data = &status;
 448        cfg_sa_add_rule.data = &status;
 449        cfg_rt_add_rule.data = &status;
 450        cfg_flow_add_rule.data = &status;
 451        cfg_neigh_add_rule.data = &status;
 452
 453        do {
 454                char oneline[1024];
 455                char *pos;
 456                get_s = fgets(oneline, 1024, f);
 457
 458                if (!get_s)
 459                        break;
 460
 461                line_num++;
 462
 463                if (strlen(oneline) > 1022) {
 464                        rte_panic("%s:%u: error: "
 465                                "the line contains more characters the parser can handle\n",
 466                                cfg_filename, line_num);
 467                        goto error_exit;
 468                }
 469
 470                /* process comment char '#' */
 471                if (oneline[0] == '#')
 472                        continue;
 473
 474                pos = strchr(oneline, '#');
 475                if (pos != NULL)
 476                        *pos = '\0';
 477
 478                /* process line concatenator '\' */
 479                pos = strchr(oneline, 92);
 480                if (pos != NULL) {
 481                        if (pos != oneline+strlen(oneline) - 2) {
 482                                rte_panic("%s:%u: error: "
 483                                        "no character should exist after '\\'\n",
 484                                        cfg_filename, line_num);
 485                                goto error_exit;
 486                        }
 487
 488                        *pos = '\0';
 489
 490                        if (strlen(oneline) + strlen(str) > 1022) {
 491                                rte_panic("%s:%u: error: "
 492                                        "the concatenated line contains more characters the parser can handle\n",
 493                                        cfg_filename, line_num);
 494                                goto error_exit;
 495                        }
 496
 497                        strcpy(str + strlen(str), oneline);
 498                        continue;
 499                }
 500
 501                /* copy the line to str and process */
 502                if (strlen(oneline) + strlen(str) > 1022) {
 503                        rte_panic("%s:%u: error: "
 504                                "the line contains more characters the parser can handle\n",
 505                                cfg_filename, line_num);
 506                        goto error_exit;
 507                }
 508                strcpy(str + strlen(str), oneline);
 509
 510                str[strlen(str)] = '\n';
 511                if (cmdline_parse(cl, str) < 0) {
 512                        rte_panic("%s:%u: error: parsing \"%s\" failed\n",
 513                                cfg_filename, line_num, str);
 514                        goto error_exit;
 515                }
 516
 517                if (status.status < 0) {
 518                        rte_panic("%s:%u: error: %s", cfg_filename,
 519                                line_num, status.parse_msg);
 520                        goto error_exit;
 521                }
 522
 523                memset(str, 0, 1024);
 524        } while (1);
 525
 526        cmdline_stdin_exit(cl);
 527        fclose(f);
 528
 529        sa_sort_arr();
 530        sp4_sort_arr();
 531        sp6_sort_arr();
 532
 533        return 0;
 534
 535error_exit:
 536        if (cl)
 537                cmdline_stdin_exit(cl);
 538        if (f)
 539                fclose(f);
 540
 541        return -1;
 542}
 543