| /* |
| * Copyright (c) 2015 Cisco and/or its affiliates. |
| * 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 <vlib/parse.h> |
| #include <vlib/unix/unix.h> |
| |
| static u8 * |
| format_value_v4_address (u8 * s, va_list * args) |
| { |
| vlib_parse_value_t *v = va_arg (*args, vlib_parse_value_t *); |
| u32 a = v->value.as_uword; |
| |
| s = format (s, "%d.%d.%d.%d", |
| (a >> 24) & 0xFF, |
| (a >> 16) & 0xFF, (a >> 8) & 0xFF, (a >> 0) & 0xFF); |
| |
| return s; |
| } |
| |
| static vlib_parse_match_t |
| v4_address_match (vlib_parse_main_t * pm, vlib_parse_type_t * type, |
| vlib_lex_token_t * t, vlib_parse_value_t * valuep) |
| { |
| u32 digit; |
| u32 value = 0; |
| int i; |
| |
| if (vec_len (pm->tokens) - (t - pm->tokens) < 7) |
| return VLIB_PARSE_MATCH_FAIL; |
| |
| /* NUMBER DOT NUMBER DOT NUMBER DOT NUMBER */ |
| |
| for (i = 0; i < 7; i++) |
| { |
| if ((i & 1) == 0) |
| { |
| if (t[i].token != VLIB_LEX_number) |
| return VLIB_PARSE_MATCH_FAIL; |
| if (t[i].value.as_uword > 0xff) |
| return VLIB_PARSE_MATCH_FAIL; |
| digit = t[i].value.as_uword; |
| value = (value << 8) | digit; |
| } |
| else |
| { |
| if (t[i].token != VLIB_LEX_dot) |
| return VLIB_PARSE_MATCH_FAIL; |
| } |
| } |
| /* note: caller advances by 1 */ |
| pm->current_token_index += 6; |
| valuep->value.as_uword = value; |
| return VLIB_PARSE_MATCH_VALUE; |
| } |
| |
| PARSE_TYPE_INIT (v4_address, v4_address_match, 0, format_value_v4_address) |
| static u8 *format_value_v4_address_and_mask (u8 * s, va_list * args) |
| { |
| vlib_parse_value_t *v = va_arg (*args, vlib_parse_value_t *); |
| u32 *a = v->value.as_pointer; |
| |
| s = format (s, "%d.%d.%d.%d", |
| (a[0] >> 24) & 0xFF, |
| (a[0] >> 16) & 0xFF, (a[0] >> 8) & 0xFF, (a[0] >> 0) & 0xFF); |
| s = format (s, "/%d", a[1]); |
| |
| return s; |
| } |
| |
| static vlib_parse_match_t |
| v4_address_and_mask_match (vlib_parse_main_t * pm, vlib_parse_type_t * type, |
| vlib_lex_token_t * t, vlib_parse_value_t * valuep) |
| { |
| u32 digit; |
| u32 address = 0; |
| u32 *rv = 0; |
| int i; |
| |
| if (vec_len (pm->tokens) - (t - pm->tokens) < 9) |
| return VLIB_PARSE_MATCH_FAIL; |
| |
| /* NUMBER DOT NUMBER DOT NUMBER DOT NUMBER */ |
| |
| for (i = 0; i < 7; i++) |
| { |
| if ((i & 1) == 0) |
| { |
| if (t[i].token != VLIB_LEX_number) |
| return VLIB_PARSE_MATCH_FAIL; |
| if (t[i].value.as_uword > 0xff) |
| return VLIB_PARSE_MATCH_FAIL; |
| digit = t[i].value.as_uword; |
| address = (address << 8) | digit; |
| } |
| else |
| { |
| if (t[i].token != VLIB_LEX_dot) |
| return VLIB_PARSE_MATCH_FAIL; |
| } |
| } |
| |
| if (t[7].token != VLIB_LEX_slash || t[8].token != VLIB_LEX_number) |
| return VLIB_PARSE_MATCH_FAIL; |
| |
| vec_add1 (rv, address); |
| vec_add1 (rv, t[8].value.as_uword); |
| |
| /* note: caller advances by 1 */ |
| pm->current_token_index += 8; |
| valuep->value.as_pointer = rv; |
| return VLIB_PARSE_MATCH_VALUE; |
| } |
| |
| void |
| v4_address_and_mask_cleanup (vlib_parse_value_t * valuep) |
| { |
| u32 *trash = valuep->value.as_pointer; |
| vec_free (trash); |
| } |
| |
| PARSE_TYPE_INIT (v4_address_and_mask, v4_address_and_mask_match, |
| v4_address_and_mask_cleanup, |
| format_value_v4_address_and_mask) |
| vlib_lex_main_t vlib_lex_main; |
| |
| |
| |
| vlib_parse_match_t eval_factor0 (vlib_parse_main_t * pm, |
| vlib_parse_item_t * item, |
| vlib_parse_value_t * value) |
| { |
| clib_warning ("%U", format_vlib_parse_value, pm); |
| return VLIB_PARSE_MATCH_RULE; |
| } |
| |
| vlib_parse_match_t |
| eval_factor1 (vlib_parse_main_t * pm, |
| vlib_parse_item_t * item, vlib_parse_value_t * value) |
| { |
| clib_warning ("%U", format_vlib_parse_value, pm); |
| return VLIB_PARSE_MATCH_RULE; |
| } |
| |
| vlib_parse_match_t |
| eval_factor2 (vlib_parse_main_t * pm, |
| vlib_parse_item_t * item, vlib_parse_value_t * value) |
| { |
| word a; |
| int index = vec_len (pm->parse_value) - 1; |
| |
| a = pm->parse_value[index].value.as_word; |
| |
| pm->parse_value[index].value.as_word = -a; |
| return VLIB_PARSE_MATCH_RULE; |
| } |
| |
| vlib_parse_match_t |
| eval_term0 (vlib_parse_main_t * pm, |
| vlib_parse_item_t * item, vlib_parse_value_t * value) |
| { |
| clib_warning ("%U", format_vlib_parse_value, pm); |
| return VLIB_PARSE_MATCH_RULE; |
| } |
| |
| vlib_parse_match_t |
| eval_term1 (vlib_parse_main_t * pm, |
| vlib_parse_item_t * item, vlib_parse_value_t * value) |
| { |
| uword a, b; |
| int index = vec_len (pm->parse_value) - 2; |
| |
| a = pm->parse_value[index].value.as_uword; |
| b = pm->parse_value[index + 1].value.as_uword; |
| |
| pm->parse_value[index].value.as_uword = a * b; |
| _vec_len (pm->parse_value) -= 1; |
| clib_warning ("%U", format_vlib_parse_value, pm); |
| |
| return VLIB_PARSE_MATCH_RULE; |
| } |
| |
| vlib_parse_match_t |
| eval_term2 (vlib_parse_main_t * pm, |
| vlib_parse_item_t * item, vlib_parse_value_t * value) |
| { |
| uword a, b; |
| int index = vec_len (pm->parse_value) - 2; |
| |
| a = pm->parse_value[index].value.as_uword; |
| b = pm->parse_value[index + 1].value.as_uword; |
| |
| pm->parse_value[index].value.as_uword = a / b; |
| _vec_len (pm->parse_value) -= 1; |
| clib_warning ("%U", format_vlib_parse_value, pm); |
| |
| return VLIB_PARSE_MATCH_RULE; |
| } |
| |
| vlib_parse_match_t |
| eval_exp0 (vlib_parse_main_t * pm, |
| vlib_parse_item_t * item, vlib_parse_value_t * value) |
| { |
| return VLIB_PARSE_MATCH_RULE; |
| } |
| |
| vlib_parse_match_t |
| eval_exp1 (vlib_parse_main_t * pm, |
| vlib_parse_item_t * item, vlib_parse_value_t * value) |
| { |
| uword a, b; |
| int index = vec_len (pm->parse_value) - 2; |
| |
| a = pm->parse_value[index].value.as_uword; |
| b = pm->parse_value[index + 1].value.as_uword; |
| |
| pm->parse_value[index].value.as_uword = a + b; |
| _vec_len (pm->parse_value) -= 1; |
| clib_warning ("%U", format_vlib_parse_value, pm); |
| |
| return VLIB_PARSE_MATCH_RULE; |
| } |
| |
| vlib_parse_match_t |
| eval_exp2 (vlib_parse_main_t * pm, |
| vlib_parse_item_t * item, vlib_parse_value_t * value) |
| { |
| uword a, b; |
| int index = vec_len (pm->parse_value) - 2; |
| |
| a = pm->parse_value[index].value.as_uword; |
| b = pm->parse_value[index + 1].value.as_uword; |
| |
| pm->parse_value[index].value.as_uword = a - b; |
| _vec_len (pm->parse_value) -= 1; |
| clib_warning ("%U", format_vlib_parse_value, pm); |
| |
| return VLIB_PARSE_MATCH_RULE; |
| } |
| |
| vlib_parse_match_t |
| eval_result (vlib_parse_main_t * pm, |
| vlib_parse_item_t * item, vlib_parse_value_t * value) |
| { |
| clib_warning ("%U", format_vlib_parse_value, pm); |
| return VLIB_PARSE_MATCH_DONE; |
| } |
| |
| vlib_parse_match_t |
| noop_match_rule (vlib_parse_main_t * pm, |
| vlib_parse_item_t * item, vlib_parse_value_t * value) |
| { |
| clib_warning ("%U", format_vlib_parse_value, pm); |
| return VLIB_PARSE_MATCH_RULE; |
| } |
| |
| #if 0 |
| PARSE_INIT (t1, "moo", eval0); |
| PARSE_INIT (t2, "moo cow mumble", eval1); |
| PARSE_INIT (t3, "moo cow", eval2); |
| PARSE_INIT (t4, "moo cow mumble grunch", eval3); |
| #endif |
| |
| #if 0 |
| PARSE_INIT (r1, "eval <exp>", eval_result); |
| |
| PARSE_INIT (r2, "<exp> = <term><exp2>", eval_exp0); |
| PARSE_INIT (r3, "<exp2> = <plus> <exp>", eval_exp1); |
| PARSE_INIT (r4, "<exp2> = <minus> <exp>", eval_exp2); |
| PARSE_INIT (r5, "<exp2> = ", noop_match_rule); |
| PARSE_TYPE_INIT (exp, rule_match, 0, 0); |
| PARSE_TYPE_INIT (exp2, rule_match, 0, 0); |
| |
| PARSE_INIT (r6, "<term> = <factor><term2>", eval_term0); |
| PARSE_INIT (r7, "<term2> = <star> <term>", eval_term1); |
| PARSE_INIT (r8, "<term2> = <slash> <term>", eval_term2); |
| PARSE_INIT (r9, "<term2> = ", noop_match_rule); |
| PARSE_TYPE_INIT (term, rule_match, 0, 0); |
| PARSE_TYPE_INIT (term2, rule_match, 0, 0); |
| |
| PARSE_INIT (r11, "<factor> = <lpar> <exp> <rpar>", eval_factor1); |
| PARSE_INIT (r10, "<factor> = <number>", eval_factor0); |
| PARSE_INIT (r12, "<factor> = <minus> <factor>", eval_factor2); |
| |
| PARSE_TYPE_INIT (factor, rule_match, 0, 0); |
| #endif |
| |
| PARSE_INIT (r1, "eval <exp>", eval_result); |
| |
| #if 1 |
| PARSE_INIT (r2, "<exp> = <term><exp2>", eval_exp0); |
| PARSE_INIT (r3, "<exp2> = <plus> <exp>", eval_exp1); |
| PARSE_INIT (r4, "<exp2> = <minus> <exp>", eval_exp2); |
| PARSE_INIT (r5, "<exp2> = ", noop_match_rule); |
| PARSE_TYPE_INIT (exp, rule_match, 0, 0); |
| PARSE_TYPE_INIT (exp2, rule_match, 0, 0); |
| |
| PARSE_INIT (r6, "<term> = <factor><term2>", eval_term0); |
| PARSE_INIT (r7, "<term2> = <star> <term>", eval_term1); |
| PARSE_INIT (r8, "<term2> = <slash> <term>", eval_term2); |
| PARSE_INIT (r9, "<term2> = ", noop_match_rule); |
| PARSE_TYPE_INIT (term, rule_match, 0, 0); |
| PARSE_TYPE_INIT (term2, rule_match, 0, 0); |
| |
| PARSE_INIT (r11, "<factor> = <lpar> <exp> <rpar>", eval_factor1); |
| PARSE_INIT (r10, "<factor> = <number>", eval_factor0); |
| PARSE_INIT (r12, "<factor> = <minus> <factor>", eval_factor2); |
| |
| PARSE_TYPE_INIT (factor, rule_match, 0, 0); |
| #endif |
| |
| #if 0 |
| PARSE_TYPE_INIT (exp, rule_match, 0, 0); |
| PARSE_INIT (r6, "<exp> = a b", eval_term0); |
| PARSE_INIT (r7, "<exp> = c d", eval_term1); |
| PARSE_INIT (r9, "<exp> = ", noop_match_rule); |
| #endif |
| |
| #if 0 |
| #define foreach_rule_evaluator \ |
| _(0) \ |
| _(1) \ |
| _(2) \ |
| _(3) |
| |
| #define _(n) \ |
| vlib_parse_match_t eval##n (vlib_parse_main_t *pm, \ |
| vlib_parse_item_t *item, \ |
| vlib_parse_value_t *value) \ |
| { \ |
| clib_warning ("%U", format_vlib_parse_value, pm); \ |
| return VLIB_PARSE_MATCH_DONE; \ |
| } |
| foreach_rule_evaluator |
| #undef _ |
| PARSE_INIT (r1, "eval <moo>", eval_result); |
| |
| PARSE_INIT (r2, "<moo> = cow", eval0); |
| PARSE_INIT (r4, "<moo> = ", eval1); |
| PARSE_TYPE_INIT (moo, rule_match, 0, 0); |
| #endif |
| |
| |
| clib_error_t * |
| test_init (vlib_main_t * vm) |
| { |
| clib_error_t *error; |
| |
| if ((error = vlib_call_init_function (vm, parse_init))) |
| return error; |
| |
| return 0; |
| } |
| |
| VLIB_INIT_FUNCTION (test_init); |
| |
| clib_error_t * |
| vlib_stdlex_init (vlib_main_t * vm) |
| { |
| vlib_lex_main_t *lm = &vlib_lex_main; |
| u16 top_index; |
| u16 slash_index, slash_star_index, slash_slash_index, slash_star_star_index; |
| u16 slash_token; |
| u16 word_index; |
| u16 zero_index, octal_index, decimal_index, hex_index, binary_index; |
| |
| top_index = vlib_lex_add_table ("top"); |
| |
| #define foreach_top_level_single_character_token \ |
| _('(', lpar) \ |
| _(')', rpar) \ |
| _(';', semi) \ |
| _('[', lbrack) \ |
| _(']', rbrack) \ |
| _('{', lcurly) \ |
| _('}', rcurly) \ |
| _('+', plus) \ |
| _('-', minus) \ |
| _('*', star) \ |
| _('%', percent) \ |
| _('@', atsign) \ |
| _(',', comma) \ |
| _('.', dot) \ |
| _('?', qmark) |
| |
| #define _(c,t) \ |
| vlib_lex_set_action_range(top_index,c,c,VLIB_LEX_RETURN,vlib_lex_add_token(lm, #t), top_index); |
| foreach_top_level_single_character_token; |
| #undef _ |
| |
| /* Numbers */ |
| zero_index = vlib_lex_add_table ("zero"); |
| octal_index = vlib_lex_add_table ("octal"); |
| decimal_index = vlib_lex_add_table ("decimal"); |
| hex_index = vlib_lex_add_table ("hex"); |
| binary_index = vlib_lex_add_table ("binary"); |
| |
| /* Support 0x 0b 0t and 0123 [octal] */ |
| vlib_lex_set_action_range (top_index, '0', '0', VLIB_LEX_START_NUMBER, 10, |
| zero_index); |
| vlib_lex_set_action_range (top_index, '1', '9', VLIB_LEX_START_NUMBER, 10, |
| decimal_index); |
| |
| vlib_lex_set_action_range (zero_index, 0, 0x7F, VLIB_LEX_RETURN_AND_RESCAN, |
| VLIB_LEX_number, top_index); |
| |
| vlib_lex_set_action_range (zero_index, 'x', 'x', VLIB_LEX_IGNORE, ~0, |
| hex_index); |
| vlib_lex_set_action_range (zero_index, 'b', 'b', VLIB_LEX_IGNORE, ~0, |
| binary_index); |
| vlib_lex_set_action_range (zero_index, 't', 't', VLIB_LEX_IGNORE, ~0, |
| decimal_index); |
| vlib_lex_set_action_range (zero_index, '0', '7', VLIB_LEX_START_NUMBER, 8, |
| octal_index); |
| |
| /* Octal */ |
| vlib_lex_set_action_range (octal_index, 0, 0x7f, VLIB_LEX_RETURN_AND_RESCAN, |
| VLIB_LEX_number, top_index); |
| vlib_lex_set_action_range (octal_index, '0', '7', VLIB_LEX_ADD_TO_NUMBER, 8, |
| octal_index); |
| |
| /* Decimal */ |
| vlib_lex_set_action_range (decimal_index, 0, 0x7f, |
| VLIB_LEX_RETURN_AND_RESCAN, VLIB_LEX_number, |
| top_index); |
| vlib_lex_set_action_range (decimal_index, '0', '9', VLIB_LEX_ADD_TO_NUMBER, |
| 10, decimal_index); |
| |
| /* Hex */ |
| vlib_lex_set_action_range (hex_index, 0, 0x7f, VLIB_LEX_RETURN_AND_RESCAN, |
| VLIB_LEX_number, top_index); |
| vlib_lex_set_action_range (hex_index, '0', '9', VLIB_LEX_ADD_TO_NUMBER, 16, |
| hex_index); |
| vlib_lex_set_action_range (hex_index, 'a', 'f', VLIB_LEX_ADD_TO_NUMBER, 16, |
| hex_index); |
| vlib_lex_set_action_range (hex_index, 'A', 'F', VLIB_LEX_ADD_TO_NUMBER, 16, |
| hex_index); |
| |
| /* Binary */ |
| vlib_lex_set_action_range (binary_index, 0, 0x7f, |
| VLIB_LEX_RETURN_AND_RESCAN, VLIB_LEX_number, |
| top_index); |
| vlib_lex_set_action_range (binary_index, '0', '1', VLIB_LEX_ADD_TO_NUMBER, |
| 2, binary_index); |
| |
| /* c/c++ comment syntax is the worst... */ |
| |
| slash_index = vlib_lex_add_table ("slash"); |
| slash_star_index = vlib_lex_add_table ("slash_star"); |
| slash_star_star_index = vlib_lex_add_table ("slash_star_star"); |
| slash_slash_index = vlib_lex_add_table ("slash_slash"); |
| slash_token = vlib_lex_add_token (lm, "slash"); |
| |
| /* Top level: see a slash, ignore, go to slash table */ |
| vlib_lex_set_action_range (top_index, '/', '/', VLIB_LEX_IGNORE, ~0, |
| slash_index); |
| |
| /* default for slash table: return SLASH, go to top table */ |
| vlib_lex_set_action_range (slash_index, 1, 0x7F, VLIB_LEX_RETURN_AND_RESCAN, |
| slash_token, top_index); |
| /* see slash-slash, go to s-s table */ |
| vlib_lex_set_action_range (slash_index, '/', '/', VLIB_LEX_IGNORE, ~0, |
| slash_slash_index); |
| /* see slash-star, go to s-* table */ |
| vlib_lex_set_action_range (slash_index, '*', '*', VLIB_LEX_IGNORE, ~0, |
| slash_star_index); |
| |
| /* EOL in s-s table, ignore, go to top table */ |
| vlib_lex_set_action_range (slash_slash_index, '\n', '\n', VLIB_LEX_IGNORE, |
| ~0, top_index); |
| |
| /* slash-star blah blah star */ |
| vlib_lex_set_action_range (slash_star_index, '*', '*', VLIB_LEX_IGNORE, ~0, |
| slash_star_star_index); |
| |
| /* slash star blah blah star slash */ |
| vlib_lex_set_action_range (slash_star_star_index, '/', '/', VLIB_LEX_IGNORE, |
| ~0, top_index); |
| |
| /* LT, =, GT */ |
| vlib_lex_set_action_range (top_index, '<', '<', VLIB_LEX_RETURN, |
| VLIB_LEX_lt, top_index); |
| vlib_lex_set_action_range (top_index, '=', '=', VLIB_LEX_RETURN, |
| VLIB_LEX_equals, top_index); |
| vlib_lex_set_action_range (top_index, '>', '>', VLIB_LEX_RETURN, |
| VLIB_LEX_gt, top_index); |
| |
| /* words, key and otherwise */ |
| word_index = vlib_lex_add_table ("word"); |
| |
| vlib_lex_set_action_range (top_index, 'a', 'z', VLIB_LEX_ADD_TO_TOKEN, ~0, |
| word_index); |
| vlib_lex_set_action_range (top_index, 'A', 'Z', VLIB_LEX_ADD_TO_TOKEN, ~0, |
| word_index); |
| |
| vlib_lex_set_action_range (word_index, 0, 0x7f, VLIB_LEX_KEYWORD_CHECK, ~0, |
| top_index); |
| |
| vlib_lex_set_action_range (word_index, 'a', 'z', VLIB_LEX_ADD_TO_TOKEN, ~0, |
| word_index); |
| vlib_lex_set_action_range (word_index, 'A', 'Z', VLIB_LEX_ADD_TO_TOKEN, ~0, |
| word_index); |
| vlib_lex_set_action_range (word_index, '_', '_', VLIB_LEX_ADD_TO_TOKEN, ~0, |
| word_index); |
| vlib_lex_set_action_range (word_index, '0', '9', VLIB_LEX_ADD_TO_TOKEN, ~0, |
| word_index); |
| |
| return 0; |
| } |
| |
| /* |
| * fd.io coding-style-patch-verification: ON |
| * |
| * Local Variables: |
| * eval: (c-set-style "gnu") |
| * End: |
| */ |