2015-12-08 15:45:58 -07:00
|
|
|
/*
|
|
|
|
|
* 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.
|
|
|
|
|
*/
|
|
|
|
|
/*
|
|
|
|
|
Copyright (c) 2001, 2002, 2003 Eliot Dresselhaus
|
|
|
|
|
|
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining
|
|
|
|
|
a copy of this software and associated documentation files (the
|
|
|
|
|
"Software"), to deal in the Software without restriction, including
|
|
|
|
|
without limitation the rights to use, copy, modify, merge, publish,
|
|
|
|
|
distribute, sublicense, and/or sell copies of the Software, and to
|
|
|
|
|
permit persons to whom the Software is furnished to do so, subject to
|
|
|
|
|
the following conditions:
|
|
|
|
|
|
|
|
|
|
The above copyright notice and this permission notice shall be
|
|
|
|
|
included in all copies or substantial portions of the Software.
|
|
|
|
|
|
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
|
|
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
|
|
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
|
|
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
|
|
|
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
|
|
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
|
|
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <vppinfra/format.h>
|
|
|
|
|
|
|
|
|
|
/* Call user's function to fill input buffer. */
|
2020-10-17 13:32:25 +02:00
|
|
|
__clib_export uword
|
2016-08-15 11:12:27 -04:00
|
|
|
_unformat_fill_input (unformat_input_t * i)
|
2015-12-08 15:45:58 -07:00
|
|
|
{
|
|
|
|
|
uword l, first_mark;
|
|
|
|
|
|
|
|
|
|
if (i->index == UNFORMAT_END_OF_INPUT)
|
|
|
|
|
return i->index;
|
|
|
|
|
|
|
|
|
|
first_mark = l = vec_len (i->buffer);
|
|
|
|
|
if (vec_len (i->buffer_marks) > 0)
|
|
|
|
|
first_mark = i->buffer_marks[0];
|
|
|
|
|
|
|
|
|
|
/* Re-use buffer when no marks. */
|
|
|
|
|
if (first_mark > 0)
|
|
|
|
|
vec_delete (i->buffer, first_mark, 0);
|
|
|
|
|
|
|
|
|
|
i->index = vec_len (i->buffer);
|
|
|
|
|
for (l = 0; l < vec_len (i->buffer_marks); l++)
|
|
|
|
|
i->buffer_marks[l] -= first_mark;
|
|
|
|
|
|
|
|
|
|
/* Call user's function to fill the buffer. */
|
|
|
|
|
if (i->fill_buffer)
|
|
|
|
|
i->index = i->fill_buffer (i);
|
|
|
|
|
|
|
|
|
|
/* If input pointer is still beyond end of buffer even after
|
|
|
|
|
fill then we've run out of input. */
|
|
|
|
|
if (i->index >= vec_len (i->buffer))
|
|
|
|
|
i->index = UNFORMAT_END_OF_INPUT;
|
|
|
|
|
|
|
|
|
|
return i->index;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
always_inline uword
|
|
|
|
|
is_white_space (uword c)
|
|
|
|
|
{
|
|
|
|
|
switch (c)
|
|
|
|
|
{
|
2016-08-15 11:12:27 -04:00
|
|
|
case ' ':
|
|
|
|
|
case '\t':
|
|
|
|
|
case '\n':
|
|
|
|
|
case '\r':
|
2015-12-08 15:45:58 -07:00
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Format function for dumping input stream. */
|
2020-10-17 13:32:25 +02:00
|
|
|
__clib_export u8 *
|
2016-08-15 11:12:27 -04:00
|
|
|
format_unformat_error (u8 * s, va_list * va)
|
2015-12-08 15:45:58 -07:00
|
|
|
{
|
2016-08-15 11:12:27 -04:00
|
|
|
unformat_input_t *i = va_arg (*va, unformat_input_t *);
|
2015-12-08 15:45:58 -07:00
|
|
|
uword l = vec_len (i->buffer);
|
|
|
|
|
|
|
|
|
|
/* Only show so much of the input buffer (it could be really large). */
|
|
|
|
|
uword n_max = 30;
|
|
|
|
|
|
|
|
|
|
if (i->index < l)
|
|
|
|
|
{
|
|
|
|
|
uword n = l - i->index;
|
2016-08-15 11:12:27 -04:00
|
|
|
u8 *p, *p_end;
|
2015-12-08 15:45:58 -07:00
|
|
|
|
|
|
|
|
p = i->buffer + i->index;
|
|
|
|
|
p_end = p + (n > n_max ? n_max : n);
|
|
|
|
|
|
|
|
|
|
/* Skip white space at end. */
|
|
|
|
|
if (n <= n_max)
|
|
|
|
|
{
|
|
|
|
|
while (p_end > p && is_white_space (p_end[-1]))
|
|
|
|
|
p_end--;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while (p < p_end)
|
|
|
|
|
{
|
|
|
|
|
switch (*p)
|
|
|
|
|
{
|
2016-08-15 11:12:27 -04:00
|
|
|
case '\r':
|
|
|
|
|
vec_add (s, "\\r", 2);
|
|
|
|
|
break;
|
|
|
|
|
case '\n':
|
|
|
|
|
vec_add (s, "\\n", 2);
|
|
|
|
|
break;
|
|
|
|
|
case '\t':
|
|
|
|
|
vec_add (s, "\\t", 2);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
vec_add1 (s, *p);
|
|
|
|
|
break;
|
2015-12-08 15:45:58 -07:00
|
|
|
}
|
|
|
|
|
p++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (n > n_max)
|
|
|
|
|
vec_add (s, "...", 3);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return s;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Print everything: not just error context. */
|
2020-10-17 13:32:25 +02:00
|
|
|
__clib_export u8 *
|
2016-08-15 11:12:27 -04:00
|
|
|
format_unformat_input (u8 * s, va_list * va)
|
2015-12-08 15:45:58 -07:00
|
|
|
{
|
2016-08-15 11:12:27 -04:00
|
|
|
unformat_input_t *i = va_arg (*va, unformat_input_t *);
|
2015-12-08 15:45:58 -07:00
|
|
|
uword l, n;
|
|
|
|
|
|
|
|
|
|
if (i->index == UNFORMAT_END_OF_INPUT)
|
|
|
|
|
s = format (s, "{END_OF_INPUT}");
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
l = vec_len (i->buffer);
|
|
|
|
|
n = l - i->index;
|
|
|
|
|
if (n > 0)
|
|
|
|
|
vec_add (s, i->buffer + i->index, n);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return s;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if CLIB_DEBUG > 0
|
2016-08-15 11:12:27 -04:00
|
|
|
void
|
|
|
|
|
di (unformat_input_t * i)
|
|
|
|
|
{
|
|
|
|
|
fformat (stderr, "%U\n", format_unformat_input, i);
|
|
|
|
|
}
|
2015-12-08 15:45:58 -07:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/* Parse delimited vector string. If string starts with { then string
|
2018-09-24 05:25:00 -07:00
|
|
|
is delimited by balanced parenthesis. Other string is delimited by
|
2015-12-08 15:45:58 -07:00
|
|
|
white space. {} were chosen since they are special to the shell. */
|
|
|
|
|
static uword
|
|
|
|
|
unformat_string (unformat_input_t * input,
|
|
|
|
|
uword delimiter_character,
|
2016-08-15 11:12:27 -04:00
|
|
|
uword format_character, va_list * va)
|
2015-12-08 15:45:58 -07:00
|
|
|
{
|
2016-08-15 11:12:27 -04:00
|
|
|
u8 **string_return = va_arg (*va, u8 **);
|
|
|
|
|
u8 *s = 0;
|
2015-12-08 15:45:58 -07:00
|
|
|
word paren = 0;
|
|
|
|
|
word is_paren_delimited = 0;
|
|
|
|
|
word backslash = 0;
|
|
|
|
|
uword c;
|
|
|
|
|
|
|
|
|
|
switch (delimiter_character)
|
|
|
|
|
{
|
|
|
|
|
case '%':
|
|
|
|
|
case ' ':
|
|
|
|
|
case '\t':
|
|
|
|
|
delimiter_character = 0;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while ((c = unformat_get_input (input)) != UNFORMAT_END_OF_INPUT)
|
|
|
|
|
{
|
|
|
|
|
word add_to_vector;
|
|
|
|
|
|
|
|
|
|
/* Null return string means to skip over delimited input. */
|
|
|
|
|
add_to_vector = string_return != 0;
|
|
|
|
|
|
|
|
|
|
if (backslash)
|
|
|
|
|
backslash = 0;
|
|
|
|
|
else
|
|
|
|
|
switch (c)
|
|
|
|
|
{
|
|
|
|
|
case '\\':
|
|
|
|
|
backslash = 1;
|
|
|
|
|
add_to_vector = 0;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case '{':
|
|
|
|
|
if (paren == 0 && vec_len (s) == 0)
|
|
|
|
|
{
|
|
|
|
|
is_paren_delimited = 1;
|
|
|
|
|
add_to_vector = 0;
|
|
|
|
|
}
|
|
|
|
|
paren++;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case '}':
|
|
|
|
|
paren--;
|
|
|
|
|
if (is_paren_delimited && paren == 0)
|
|
|
|
|
goto done;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ' ':
|
|
|
|
|
case '\t':
|
|
|
|
|
case '\n':
|
|
|
|
|
case '\r':
|
2016-08-15 11:12:27 -04:00
|
|
|
if (!is_paren_delimited)
|
2015-12-08 15:45:58 -07:00
|
|
|
{
|
|
|
|
|
unformat_put_input (input);
|
|
|
|
|
goto done;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
2016-08-15 11:12:27 -04:00
|
|
|
if (!is_paren_delimited && c == delimiter_character)
|
2015-12-08 15:45:58 -07:00
|
|
|
{
|
|
|
|
|
unformat_put_input (input);
|
|
|
|
|
goto done;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (add_to_vector)
|
|
|
|
|
vec_add1 (s, c);
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-15 11:12:27 -04:00
|
|
|
done:
|
2015-12-08 15:45:58 -07:00
|
|
|
if (string_return)
|
|
|
|
|
{
|
|
|
|
|
/* Match the string { END-OF-INPUT as a single brace. */
|
|
|
|
|
if (c == UNFORMAT_END_OF_INPUT && vec_len (s) == 0 && paren == 1)
|
2016-08-15 11:12:27 -04:00
|
|
|
vec_add1 (s, '{');
|
2015-12-08 15:45:58 -07:00
|
|
|
|
|
|
|
|
/* Don't match null string. */
|
|
|
|
|
if (c == UNFORMAT_END_OF_INPUT && vec_len (s) == 0)
|
|
|
|
|
return 0;
|
2016-08-15 11:12:27 -04:00
|
|
|
|
2015-12-08 15:45:58 -07:00
|
|
|
/* Null terminate C string. */
|
|
|
|
|
if (format_character == 's')
|
|
|
|
|
vec_add1 (s, 0);
|
|
|
|
|
|
|
|
|
|
*string_return = s;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
vec_free (s); /* just to make sure */
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-17 13:32:25 +02:00
|
|
|
__clib_export uword
|
2016-08-15 11:12:27 -04:00
|
|
|
unformat_hex_string (unformat_input_t * input, va_list * va)
|
2015-12-08 15:45:58 -07:00
|
|
|
{
|
2016-08-15 11:12:27 -04:00
|
|
|
u8 **hexstring_return = va_arg (*va, u8 **);
|
|
|
|
|
u8 *s;
|
2015-12-08 15:45:58 -07:00
|
|
|
uword n, d, c;
|
|
|
|
|
|
|
|
|
|
n = 0;
|
|
|
|
|
d = 0;
|
|
|
|
|
s = 0;
|
|
|
|
|
while ((c = unformat_get_input (input)) != UNFORMAT_END_OF_INPUT)
|
|
|
|
|
{
|
|
|
|
|
if (c >= '0' && c <= '9')
|
2016-08-15 11:12:27 -04:00
|
|
|
d = 16 * d + c - '0';
|
2015-12-08 15:45:58 -07:00
|
|
|
else if (c >= 'a' && c <= 'f')
|
2016-08-15 11:12:27 -04:00
|
|
|
d = 16 * d + 10 + c - 'a';
|
2015-12-08 15:45:58 -07:00
|
|
|
else if (c >= 'A' && c <= 'F')
|
2016-08-15 11:12:27 -04:00
|
|
|
d = 16 * d + 10 + c - 'A';
|
2015-12-08 15:45:58 -07:00
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
unformat_put_input (input);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
n++;
|
|
|
|
|
|
|
|
|
|
if (n == 2)
|
|
|
|
|
{
|
|
|
|
|
vec_add1 (s, d);
|
|
|
|
|
n = d = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Hex string must have even number of digits. */
|
|
|
|
|
if (n % 2)
|
|
|
|
|
{
|
|
|
|
|
vec_free (s);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2017-02-15 09:03:06 -05:00
|
|
|
/* Make sure something was processed. */
|
|
|
|
|
else if (s == 0)
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2015-12-08 15:45:58 -07:00
|
|
|
|
|
|
|
|
*hexstring_return = s;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* unformat (input "foo%U", unformat_eof) matches terminal foo only */
|
2020-10-17 13:32:25 +02:00
|
|
|
__clib_export uword
|
2015-12-08 15:45:58 -07:00
|
|
|
unformat_eof (unformat_input_t * input, va_list * va)
|
|
|
|
|
{
|
|
|
|
|
return unformat_check_input (input) == UNFORMAT_END_OF_INPUT;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Parse a token containing given set of characters. */
|
2020-10-17 13:32:25 +02:00
|
|
|
__clib_export uword
|
2016-08-15 11:12:27 -04:00
|
|
|
unformat_token (unformat_input_t * input, va_list * va)
|
2015-12-08 15:45:58 -07:00
|
|
|
{
|
2016-08-15 11:12:27 -04:00
|
|
|
u8 *token_chars = va_arg (*va, u8 *);
|
|
|
|
|
u8 **string_return = va_arg (*va, u8 **);
|
|
|
|
|
u8 *s, map[256];
|
2015-12-08 15:45:58 -07:00
|
|
|
uword i, c;
|
|
|
|
|
|
2016-08-15 11:12:27 -04:00
|
|
|
if (!token_chars)
|
2015-12-08 15:45:58 -07:00
|
|
|
token_chars = (u8 *) "a-zA-Z0-9_";
|
|
|
|
|
|
2018-10-17 10:38:51 -04:00
|
|
|
clib_memset (map, 0, sizeof (map));
|
2016-08-15 11:12:27 -04:00
|
|
|
for (s = token_chars; *s;)
|
2015-12-08 15:45:58 -07:00
|
|
|
{
|
2019-04-18 17:42:24 +02:00
|
|
|
/*
|
|
|
|
|
* Parse range.
|
|
|
|
|
* The test order is important: s[1] is valid because s[0] != '\0' but
|
|
|
|
|
* s[2] might not if s[1] == '\0'
|
|
|
|
|
* Also, if s[1] == '-' but s[2] == '\0' the test s[0] < s[2] will
|
|
|
|
|
* (correctly) fail
|
|
|
|
|
*/
|
|
|
|
|
if (s[1] == '-' && s[0] < s[2])
|
2015-12-08 15:45:58 -07:00
|
|
|
{
|
|
|
|
|
for (i = s[0]; i <= s[2]; i++)
|
|
|
|
|
map[i] = 1;
|
|
|
|
|
s = s + 3;
|
2016-08-15 11:12:27 -04:00
|
|
|
}
|
2015-12-08 15:45:58 -07:00
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
map[s[0]] = 1;
|
|
|
|
|
s = s + 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
s = 0;
|
|
|
|
|
while ((c = unformat_get_input (input)) != UNFORMAT_END_OF_INPUT)
|
|
|
|
|
{
|
2016-08-15 11:12:27 -04:00
|
|
|
if (!map[c])
|
2015-12-08 15:45:58 -07:00
|
|
|
{
|
|
|
|
|
unformat_put_input (input);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2016-08-15 11:12:27 -04:00
|
|
|
|
2015-12-08 15:45:58 -07:00
|
|
|
vec_add1 (s, c);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (vec_len (s) == 0)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
*string_return = s;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Unformat (parse) function which reads a %s string and converts it
|
|
|
|
|
to and unformat_input_t. */
|
2020-10-17 13:32:25 +02:00
|
|
|
__clib_export uword
|
2016-08-15 11:12:27 -04:00
|
|
|
unformat_input (unformat_input_t * i, va_list * args)
|
2015-12-08 15:45:58 -07:00
|
|
|
{
|
2016-08-15 11:12:27 -04:00
|
|
|
unformat_input_t *sub_input = va_arg (*args, unformat_input_t *);
|
|
|
|
|
u8 *s;
|
2015-12-08 15:45:58 -07:00
|
|
|
|
|
|
|
|
if (unformat (i, "%v", &s))
|
|
|
|
|
{
|
|
|
|
|
unformat_init_vector (sub_input, s);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Parse a line ending with \n and return it. */
|
2020-10-17 13:32:25 +02:00
|
|
|
__clib_export uword
|
2016-08-15 11:12:27 -04:00
|
|
|
unformat_line (unformat_input_t * i, va_list * va)
|
2015-12-08 15:45:58 -07:00
|
|
|
{
|
2016-08-15 11:12:27 -04:00
|
|
|
u8 *line = 0, **result = va_arg (*va, u8 **);
|
2015-12-08 15:45:58 -07:00
|
|
|
uword c;
|
|
|
|
|
|
2016-08-15 11:12:27 -04:00
|
|
|
while ((c = unformat_get_input (i)) != '\n' && c != UNFORMAT_END_OF_INPUT)
|
2015-12-08 15:45:58 -07:00
|
|
|
{
|
|
|
|
|
vec_add1 (line, c);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*result = line;
|
2017-07-10 18:23:31 +03:00
|
|
|
return vec_len (line);
|
2015-12-08 15:45:58 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Parse a line ending with \n and return it as an unformat_input_t. */
|
2020-10-17 13:32:25 +02:00
|
|
|
__clib_export uword
|
2016-08-15 11:12:27 -04:00
|
|
|
unformat_line_input (unformat_input_t * i, va_list * va)
|
2015-12-08 15:45:58 -07:00
|
|
|
{
|
2016-08-15 11:12:27 -04:00
|
|
|
unformat_input_t *result = va_arg (*va, unformat_input_t *);
|
|
|
|
|
u8 *line;
|
2017-07-10 18:23:31 +03:00
|
|
|
if (!unformat_user (i, unformat_line, &line))
|
|
|
|
|
return 0;
|
2015-12-08 15:45:58 -07:00
|
|
|
unformat_init_vector (result, line);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Values for is_signed. */
|
|
|
|
|
#define UNFORMAT_INTEGER_SIGNED 1
|
|
|
|
|
#define UNFORMAT_INTEGER_UNSIGNED 0
|
|
|
|
|
|
|
|
|
|
static uword
|
|
|
|
|
unformat_integer (unformat_input_t * input,
|
2016-08-15 11:12:27 -04:00
|
|
|
va_list * va, uword base, uword is_signed, uword data_bytes)
|
2015-12-08 15:45:58 -07:00
|
|
|
{
|
|
|
|
|
uword c, digit;
|
|
|
|
|
uword value = 0;
|
|
|
|
|
uword n_digits = 0;
|
|
|
|
|
uword n_input = 0;
|
|
|
|
|
uword sign = 0;
|
|
|
|
|
|
|
|
|
|
/* We only support bases <= 64. */
|
|
|
|
|
if (base < 2 || base > 64)
|
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
|
|
while ((c = unformat_get_input (input)) != UNFORMAT_END_OF_INPUT)
|
|
|
|
|
{
|
|
|
|
|
switch (c)
|
|
|
|
|
{
|
|
|
|
|
case '-':
|
|
|
|
|
if (n_input == 0)
|
|
|
|
|
{
|
|
|
|
|
if (is_signed)
|
|
|
|
|
{
|
|
|
|
|
sign = 1;
|
|
|
|
|
goto next_digit;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
/* Leading sign for unsigned number. */
|
|
|
|
|
goto error;
|
|
|
|
|
}
|
|
|
|
|
/* Sign after input (e.g. 100-200). */
|
|
|
|
|
goto put_input_done;
|
|
|
|
|
|
|
|
|
|
case '+':
|
2016-08-15 11:12:27 -04:00
|
|
|
if (n_input > 0)
|
2015-12-08 15:45:58 -07:00
|
|
|
goto put_input_done;
|
|
|
|
|
sign = 0;
|
|
|
|
|
goto next_digit;
|
|
|
|
|
|
|
|
|
|
case '0' ... '9':
|
|
|
|
|
digit = c - '0';
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 'a' ... 'z':
|
|
|
|
|
digit = 10 + (c - 'a');
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 'A' ... 'Z':
|
|
|
|
|
digit = 10 + (base >= 36 ? 26 : 0) + (c - 'A');
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case '/':
|
|
|
|
|
digit = 62;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case '?':
|
|
|
|
|
digit = 63;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
goto put_input_done;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (digit >= base)
|
|
|
|
|
{
|
|
|
|
|
put_input_done:
|
|
|
|
|
unformat_put_input (input);
|
|
|
|
|
goto done;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
2016-08-15 11:12:27 -04:00
|
|
|
uword new_value = base * value + digit;
|
2015-12-08 15:45:58 -07:00
|
|
|
|
|
|
|
|
/* Check for overflow. */
|
|
|
|
|
if (new_value < value)
|
|
|
|
|
goto error;
|
|
|
|
|
value = new_value;
|
|
|
|
|
}
|
|
|
|
|
n_digits += 1;
|
|
|
|
|
|
|
|
|
|
next_digit:
|
|
|
|
|
n_input++;
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-15 11:12:27 -04:00
|
|
|
done:
|
2015-12-08 15:45:58 -07:00
|
|
|
if (sign)
|
|
|
|
|
value = -value;
|
|
|
|
|
|
|
|
|
|
if (n_digits > 0)
|
|
|
|
|
{
|
2016-08-15 11:12:27 -04:00
|
|
|
void *v = va_arg (*va, void *);
|
2015-12-08 15:45:58 -07:00
|
|
|
|
|
|
|
|
if (data_bytes == ~0)
|
2016-08-15 11:12:27 -04:00
|
|
|
data_bytes = sizeof (int);
|
2015-12-08 15:45:58 -07:00
|
|
|
|
|
|
|
|
switch (data_bytes)
|
|
|
|
|
{
|
2016-08-15 11:12:27 -04:00
|
|
|
case 1:
|
|
|
|
|
*(u8 *) v = value;
|
|
|
|
|
break;
|
|
|
|
|
case 2:
|
|
|
|
|
*(u16 *) v = value;
|
|
|
|
|
break;
|
|
|
|
|
case 4:
|
|
|
|
|
*(u32 *) v = value;
|
|
|
|
|
break;
|
|
|
|
|
case 8:
|
|
|
|
|
*(u64 *) v = value;
|
|
|
|
|
break;
|
2015-12-08 15:45:58 -07:00
|
|
|
default:
|
2016-08-15 11:12:27 -04:00
|
|
|
goto error;
|
2015-12-08 15:45:58 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-15 11:12:27 -04:00
|
|
|
error:
|
2015-12-08 15:45:58 -07:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Return x 10^n */
|
2016-08-15 11:12:27 -04:00
|
|
|
static f64
|
|
|
|
|
times_power_of_ten (f64 x, int n)
|
2015-12-08 15:45:58 -07:00
|
|
|
{
|
|
|
|
|
if (n >= 0)
|
|
|
|
|
{
|
|
|
|
|
static f64 t[8] = { 1e+0, 1e+1, 1e+2, 1e+3, 1e+4, 1e+5, 1e+6, 1e+7, };
|
|
|
|
|
while (n >= 8)
|
|
|
|
|
{
|
|
|
|
|
x *= 1e+8;
|
|
|
|
|
n -= 8;
|
|
|
|
|
}
|
|
|
|
|
return x * t[n];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
static f64 t[8] = { 1e-0, 1e-1, 1e-2, 1e-3, 1e-4, 1e-5, 1e-6, 1e-7, };
|
|
|
|
|
while (n <= -8)
|
|
|
|
|
{
|
|
|
|
|
x *= 1e-8;
|
|
|
|
|
n += 8;
|
|
|
|
|
}
|
|
|
|
|
return x * t[-n];
|
|
|
|
|
}
|
2016-08-15 11:12:27 -04:00
|
|
|
|
2015-12-08 15:45:58 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static uword
|
2016-08-15 11:12:27 -04:00
|
|
|
unformat_float (unformat_input_t * input, va_list * va)
|
2015-12-08 15:45:58 -07:00
|
|
|
{
|
|
|
|
|
uword c;
|
|
|
|
|
u64 values[3];
|
|
|
|
|
uword n_digits[3], value_index = 0;
|
|
|
|
|
uword signs[2], sign_index = 0;
|
|
|
|
|
uword n_input = 0;
|
|
|
|
|
|
2018-10-17 10:38:51 -04:00
|
|
|
clib_memset (values, 0, sizeof (values));
|
|
|
|
|
clib_memset (n_digits, 0, sizeof (n_digits));
|
|
|
|
|
clib_memset (signs, 0, sizeof (signs));
|
2015-12-08 15:45:58 -07:00
|
|
|
|
|
|
|
|
while ((c = unformat_get_input (input)) != UNFORMAT_END_OF_INPUT)
|
|
|
|
|
{
|
|
|
|
|
switch (c)
|
|
|
|
|
{
|
|
|
|
|
case '-':
|
|
|
|
|
if (value_index == 2 && n_digits[2] == 0)
|
2016-08-15 11:12:27 -04:00
|
|
|
/* sign of exponent: it's ok. */ ;
|
2015-12-08 15:45:58 -07:00
|
|
|
|
|
|
|
|
else if (value_index < 2 && n_digits[0] > 0)
|
|
|
|
|
{
|
|
|
|
|
/* 123- */
|
|
|
|
|
unformat_put_input (input);
|
|
|
|
|
goto done;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else if (n_input > 0)
|
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
|
|
signs[sign_index++] = 1;
|
|
|
|
|
goto next_digit;
|
|
|
|
|
|
|
|
|
|
case '+':
|
|
|
|
|
if (value_index == 2 && n_digits[2] == 0)
|
2016-08-15 11:12:27 -04:00
|
|
|
/* sign of exponent: it's ok. */ ;
|
2015-12-08 15:45:58 -07:00
|
|
|
|
|
|
|
|
else if (value_index < 2 && n_digits[0] > 0)
|
|
|
|
|
{
|
|
|
|
|
/* 123+ */
|
|
|
|
|
unformat_put_input (input);
|
|
|
|
|
goto done;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else if (n_input > 0)
|
|
|
|
|
goto error;
|
|
|
|
|
signs[sign_index++] = 0;
|
|
|
|
|
goto next_digit;
|
|
|
|
|
|
|
|
|
|
case 'e':
|
|
|
|
|
case 'E':
|
|
|
|
|
if (n_input == 0)
|
|
|
|
|
goto error;
|
|
|
|
|
value_index = 2;
|
|
|
|
|
sign_index = 1;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case '.':
|
|
|
|
|
if (value_index > 0)
|
|
|
|
|
goto error;
|
|
|
|
|
value_index = 1;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case '0' ... '9':
|
|
|
|
|
{
|
|
|
|
|
u64 tmp;
|
|
|
|
|
|
|
|
|
|
tmp = values[value_index] * 10 + c - '0';
|
|
|
|
|
|
|
|
|
|
/* Check for overflow. */
|
|
|
|
|
if (tmp < values[value_index])
|
|
|
|
|
goto error;
|
|
|
|
|
values[value_index] = tmp;
|
|
|
|
|
n_digits[value_index] += 1;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
unformat_put_input (input);
|
|
|
|
|
goto done;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
next_digit:
|
|
|
|
|
n_input++;
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-15 11:12:27 -04:00
|
|
|
done:
|
2015-12-08 15:45:58 -07:00
|
|
|
{
|
2016-08-15 11:12:27 -04:00
|
|
|
f64 f_values[2], *value_return;
|
2015-12-08 15:45:58 -07:00
|
|
|
word expon;
|
|
|
|
|
|
|
|
|
|
/* Must have either whole or fraction digits. */
|
|
|
|
|
if (n_digits[0] + n_digits[1] <= 0)
|
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
|
|
f_values[0] = values[0];
|
|
|
|
|
if (signs[0])
|
|
|
|
|
f_values[0] = -f_values[0];
|
|
|
|
|
|
|
|
|
|
f_values[1] = values[1];
|
|
|
|
|
f_values[1] = times_power_of_ten (f_values[1], -n_digits[1]);
|
|
|
|
|
|
|
|
|
|
f_values[0] += f_values[1];
|
|
|
|
|
|
|
|
|
|
expon = values[2];
|
|
|
|
|
if (signs[1])
|
|
|
|
|
expon = -expon;
|
|
|
|
|
|
|
|
|
|
f_values[0] = times_power_of_ten (f_values[0], expon);
|
|
|
|
|
|
|
|
|
|
value_return = va_arg (*va, f64 *);
|
|
|
|
|
*value_return = f_values[0];
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-15 11:12:27 -04:00
|
|
|
error:
|
2015-12-08 15:45:58 -07:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
IP Multicast FIB (mfib)
- IPv[46] mfib tables with support for (*,G/m), (*,G) and (S,G) exact and longest prefix match
- Replication represented via a new replicate DPO.
- RPF configuration and data-plane checking
- data-plane signals sent to listening control planes.
The functions of multicast forwarding entries differ from their unicast conterparts, so we introduce a new mfib_table_t and mfib_entry_t objects. However, we re-use the fib_path_list to resolve and build the entry's output list. the fib_path_list provides the service to construct a replicate DPO for multicast.
'make tests' is added to with two new suites; TEST=mfib, this is invocation of the CLI command 'test mfib' which deals with many path add/remove, flag set/unset scenarios, TEST=ip-mcast, data-plane forwarding tests.
Updated applications to use the new MIFB functions;
- IPv6 NS/RA.
- DHCPv6
unit tests for these are undated accordingly.
Change-Id: I49ec37b01f1b170335a5697541c8fd30e6d3a961
Signed-off-by: Neale Ranns <nranns@cisco.com>
2016-11-22 17:07:28 +00:00
|
|
|
static const char *
|
|
|
|
|
match_input_with_format (unformat_input_t * input, const char *f)
|
2015-12-08 15:45:58 -07:00
|
|
|
{
|
|
|
|
|
uword cf, ci;
|
|
|
|
|
|
|
|
|
|
ASSERT (*f != 0);
|
|
|
|
|
|
|
|
|
|
while (1)
|
|
|
|
|
{
|
|
|
|
|
cf = *f;
|
|
|
|
|
if (cf == 0 || cf == '%' || cf == ' ')
|
|
|
|
|
break;
|
|
|
|
|
f++;
|
|
|
|
|
|
|
|
|
|
ci = unformat_get_input (input);
|
|
|
|
|
|
|
|
|
|
if (cf != ci)
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
return f;
|
|
|
|
|
}
|
|
|
|
|
|
IP Multicast FIB (mfib)
- IPv[46] mfib tables with support for (*,G/m), (*,G) and (S,G) exact and longest prefix match
- Replication represented via a new replicate DPO.
- RPF configuration and data-plane checking
- data-plane signals sent to listening control planes.
The functions of multicast forwarding entries differ from their unicast conterparts, so we introduce a new mfib_table_t and mfib_entry_t objects. However, we re-use the fib_path_list to resolve and build the entry's output list. the fib_path_list provides the service to construct a replicate DPO for multicast.
'make tests' is added to with two new suites; TEST=mfib, this is invocation of the CLI command 'test mfib' which deals with many path add/remove, flag set/unset scenarios, TEST=ip-mcast, data-plane forwarding tests.
Updated applications to use the new MIFB functions;
- IPv6 NS/RA.
- DHCPv6
unit tests for these are undated accordingly.
Change-Id: I49ec37b01f1b170335a5697541c8fd30e6d3a961
Signed-off-by: Neale Ranns <nranns@cisco.com>
2016-11-22 17:07:28 +00:00
|
|
|
static const char *
|
|
|
|
|
do_percent (unformat_input_t * input, va_list * va, const char *f)
|
2015-12-08 15:45:58 -07:00
|
|
|
{
|
|
|
|
|
uword cf, n, data_bytes = ~0;
|
|
|
|
|
|
|
|
|
|
cf = *f++;
|
|
|
|
|
|
|
|
|
|
switch (cf)
|
|
|
|
|
{
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 'w':
|
|
|
|
|
/* Word types. */
|
|
|
|
|
cf = *f++;
|
|
|
|
|
data_bytes = sizeof (uword);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 'l':
|
|
|
|
|
cf = *f++;
|
|
|
|
|
if (cf == 'l')
|
|
|
|
|
{
|
|
|
|
|
cf = *f++;
|
|
|
|
|
data_bytes = sizeof (long long);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
data_bytes = sizeof (long);
|
|
|
|
|
}
|
|
|
|
|
break;
|
2016-08-15 11:12:27 -04:00
|
|
|
|
2015-12-08 15:45:58 -07:00
|
|
|
case 'L':
|
|
|
|
|
cf = *f++;
|
|
|
|
|
data_bytes = sizeof (long long);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
n = 0;
|
|
|
|
|
switch (cf)
|
|
|
|
|
{
|
|
|
|
|
case 'D':
|
|
|
|
|
data_bytes = va_arg (*va, int);
|
|
|
|
|
case 'd':
|
|
|
|
|
n = unformat_integer (input, va, 10,
|
|
|
|
|
UNFORMAT_INTEGER_SIGNED, data_bytes);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 'u':
|
|
|
|
|
n = unformat_integer (input, va, 10,
|
|
|
|
|
UNFORMAT_INTEGER_UNSIGNED, data_bytes);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 'b':
|
|
|
|
|
n = unformat_integer (input, va, 2,
|
|
|
|
|
UNFORMAT_INTEGER_UNSIGNED, data_bytes);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 'o':
|
|
|
|
|
n = unformat_integer (input, va, 8,
|
|
|
|
|
UNFORMAT_INTEGER_UNSIGNED, data_bytes);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 'X':
|
|
|
|
|
data_bytes = va_arg (*va, int);
|
|
|
|
|
case 'x':
|
|
|
|
|
n = unformat_integer (input, va, 16,
|
|
|
|
|
UNFORMAT_INTEGER_UNSIGNED, data_bytes);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 'f':
|
|
|
|
|
n = unformat_float (input, va);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 's':
|
|
|
|
|
case 'v':
|
|
|
|
|
n = unformat_string (input, f[0], cf, va);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 'U':
|
|
|
|
|
{
|
2016-08-15 11:12:27 -04:00
|
|
|
unformat_function_t *f = va_arg (*va, unformat_function_t *);
|
2015-12-08 15:45:58 -07:00
|
|
|
n = f (input, va);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case '=':
|
|
|
|
|
case '|':
|
|
|
|
|
{
|
2016-08-15 11:12:27 -04:00
|
|
|
int *var = va_arg (*va, int *);
|
2015-12-08 15:45:58 -07:00
|
|
|
uword val = va_arg (*va, int);
|
|
|
|
|
|
|
|
|
|
if (cf == '|')
|
|
|
|
|
val |= *var;
|
|
|
|
|
*var = val;
|
|
|
|
|
n = 1;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return n ? f : 0;
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-17 13:32:25 +02:00
|
|
|
__clib_export uword
|
2016-08-15 11:12:27 -04:00
|
|
|
unformat_skip_white_space (unformat_input_t * input)
|
2015-12-08 15:45:58 -07:00
|
|
|
{
|
|
|
|
|
uword n = 0;
|
|
|
|
|
uword c;
|
|
|
|
|
|
|
|
|
|
while ((c = unformat_get_input (input)) != UNFORMAT_END_OF_INPUT)
|
|
|
|
|
{
|
2016-08-15 11:12:27 -04:00
|
|
|
if (!is_white_space (c))
|
2015-12-08 15:45:58 -07:00
|
|
|
{
|
|
|
|
|
unformat_put_input (input);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
n++;
|
|
|
|
|
}
|
|
|
|
|
return n;
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-22 13:29:28 +02:00
|
|
|
__clib_export uword
|
IP Multicast FIB (mfib)
- IPv[46] mfib tables with support for (*,G/m), (*,G) and (S,G) exact and longest prefix match
- Replication represented via a new replicate DPO.
- RPF configuration and data-plane checking
- data-plane signals sent to listening control planes.
The functions of multicast forwarding entries differ from their unicast conterparts, so we introduce a new mfib_table_t and mfib_entry_t objects. However, we re-use the fib_path_list to resolve and build the entry's output list. the fib_path_list provides the service to construct a replicate DPO for multicast.
'make tests' is added to with two new suites; TEST=mfib, this is invocation of the CLI command 'test mfib' which deals with many path add/remove, flag set/unset scenarios, TEST=ip-mcast, data-plane forwarding tests.
Updated applications to use the new MIFB functions;
- IPv6 NS/RA.
- DHCPv6
unit tests for these are undated accordingly.
Change-Id: I49ec37b01f1b170335a5697541c8fd30e6d3a961
Signed-off-by: Neale Ranns <nranns@cisco.com>
2016-11-22 17:07:28 +00:00
|
|
|
va_unformat (unformat_input_t * input, const char *fmt, va_list * va)
|
2015-12-08 15:45:58 -07:00
|
|
|
{
|
IP Multicast FIB (mfib)
- IPv[46] mfib tables with support for (*,G/m), (*,G) and (S,G) exact and longest prefix match
- Replication represented via a new replicate DPO.
- RPF configuration and data-plane checking
- data-plane signals sent to listening control planes.
The functions of multicast forwarding entries differ from their unicast conterparts, so we introduce a new mfib_table_t and mfib_entry_t objects. However, we re-use the fib_path_list to resolve and build the entry's output list. the fib_path_list provides the service to construct a replicate DPO for multicast.
'make tests' is added to with two new suites; TEST=mfib, this is invocation of the CLI command 'test mfib' which deals with many path add/remove, flag set/unset scenarios, TEST=ip-mcast, data-plane forwarding tests.
Updated applications to use the new MIFB functions;
- IPv6 NS/RA.
- DHCPv6
unit tests for these are undated accordingly.
Change-Id: I49ec37b01f1b170335a5697541c8fd30e6d3a961
Signed-off-by: Neale Ranns <nranns@cisco.com>
2016-11-22 17:07:28 +00:00
|
|
|
const char *f;
|
2015-12-08 15:45:58 -07:00
|
|
|
uword input_matches_format;
|
|
|
|
|
uword default_skip_input_white_space;
|
|
|
|
|
uword n_input_white_space_skipped;
|
|
|
|
|
uword last_non_white_space_match_percent;
|
|
|
|
|
uword last_non_white_space_match_format;
|
|
|
|
|
|
2016-08-15 11:12:27 -04:00
|
|
|
vec_add1_aligned (input->buffer_marks, input->index,
|
|
|
|
|
sizeof (input->buffer_marks[0]));
|
2015-12-08 15:45:58 -07:00
|
|
|
|
|
|
|
|
f = fmt;
|
|
|
|
|
default_skip_input_white_space = 1;
|
|
|
|
|
input_matches_format = 0;
|
|
|
|
|
last_non_white_space_match_percent = 0;
|
|
|
|
|
last_non_white_space_match_format = 0;
|
2016-08-15 11:12:27 -04:00
|
|
|
|
2015-12-08 15:45:58 -07:00
|
|
|
while (1)
|
|
|
|
|
{
|
|
|
|
|
char cf;
|
|
|
|
|
uword is_percent, skip_input_white_space;
|
|
|
|
|
|
|
|
|
|
cf = *f;
|
|
|
|
|
is_percent = 0;
|
|
|
|
|
|
|
|
|
|
/* Always skip input white space at start of format string.
|
2016-08-15 11:12:27 -04:00
|
|
|
Otherwise use default skip value which can be changed by %_
|
|
|
|
|
(see below). */
|
2015-12-08 15:45:58 -07:00
|
|
|
skip_input_white_space = f == fmt || default_skip_input_white_space;
|
|
|
|
|
|
|
|
|
|
/* Spaces in format request skipping input white space. */
|
|
|
|
|
if (is_white_space (cf))
|
|
|
|
|
{
|
|
|
|
|
skip_input_white_space = 1;
|
|
|
|
|
|
|
|
|
|
/* Multiple format spaces are equivalent to a single white
|
|
|
|
|
space. */
|
|
|
|
|
while (is_white_space (*++f))
|
|
|
|
|
;
|
|
|
|
|
}
|
|
|
|
|
else if (cf == '%')
|
|
|
|
|
{
|
|
|
|
|
/* %_ toggles whether or not to skip input white space. */
|
|
|
|
|
switch (*++f)
|
|
|
|
|
{
|
|
|
|
|
case '_':
|
2016-08-15 11:12:27 -04:00
|
|
|
default_skip_input_white_space =
|
|
|
|
|
!default_skip_input_white_space;
|
2015-12-08 15:45:58 -07:00
|
|
|
f++;
|
|
|
|
|
/* For transition from skip to no-skip in middle of format
|
2016-08-15 11:12:27 -04:00
|
|
|
string, skip input white space. For example, the following matches:
|
|
|
|
|
fmt = "%_%d.%d%_->%_%d.%d%_"
|
|
|
|
|
input "1.2 -> 3.4"
|
|
|
|
|
Without this the space after -> does not get skipped. */
|
|
|
|
|
if (!default_skip_input_white_space
|
|
|
|
|
&& !(f == fmt + 2 || *f == 0))
|
2015-12-08 15:45:58 -07:00
|
|
|
unformat_skip_white_space (input);
|
|
|
|
|
continue;
|
|
|
|
|
|
2016-08-15 11:12:27 -04:00
|
|
|
/* %% means match % */
|
2015-12-08 15:45:58 -07:00
|
|
|
case '%':
|
|
|
|
|
break;
|
|
|
|
|
|
2016-08-15 11:12:27 -04:00
|
|
|
/* % at end of format string. */
|
2015-12-08 15:45:58 -07:00
|
|
|
case 0:
|
|
|
|
|
goto parse_fail;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
is_percent = 1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
n_input_white_space_skipped = 0;
|
|
|
|
|
if (skip_input_white_space)
|
|
|
|
|
n_input_white_space_skipped = unformat_skip_white_space (input);
|
|
|
|
|
|
|
|
|
|
/* End of format string. */
|
|
|
|
|
if (cf == 0)
|
|
|
|
|
{
|
|
|
|
|
/* Force parse error when format string ends and input is
|
|
|
|
|
not white or at end. As an example, this is to prevent
|
|
|
|
|
format "foo" from matching input "food".
|
|
|
|
|
The last_non_white_space_match_percent is to make
|
|
|
|
|
"foo %d" match input "foo 10,bletch" with %d matching 10. */
|
|
|
|
|
if (skip_input_white_space
|
2016-08-15 11:12:27 -04:00
|
|
|
&& !last_non_white_space_match_percent
|
|
|
|
|
&& !last_non_white_space_match_format
|
2015-12-08 15:45:58 -07:00
|
|
|
&& n_input_white_space_skipped == 0
|
|
|
|
|
&& input->index != UNFORMAT_END_OF_INPUT)
|
|
|
|
|
goto parse_fail;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
last_non_white_space_match_percent = is_percent;
|
|
|
|
|
last_non_white_space_match_format = 0;
|
|
|
|
|
|
|
|
|
|
/* Explicit spaces in format must match input white space. */
|
|
|
|
|
if (cf == ' ' && !default_skip_input_white_space)
|
|
|
|
|
{
|
|
|
|
|
if (n_input_white_space_skipped == 0)
|
|
|
|
|
goto parse_fail;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else if (is_percent)
|
|
|
|
|
{
|
2016-08-15 11:12:27 -04:00
|
|
|
if (!(f = do_percent (input, va, f)))
|
2015-12-08 15:45:58 -07:00
|
|
|
goto parse_fail;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else
|
|
|
|
|
{
|
IP Multicast FIB (mfib)
- IPv[46] mfib tables with support for (*,G/m), (*,G) and (S,G) exact and longest prefix match
- Replication represented via a new replicate DPO.
- RPF configuration and data-plane checking
- data-plane signals sent to listening control planes.
The functions of multicast forwarding entries differ from their unicast conterparts, so we introduce a new mfib_table_t and mfib_entry_t objects. However, we re-use the fib_path_list to resolve and build the entry's output list. the fib_path_list provides the service to construct a replicate DPO for multicast.
'make tests' is added to with two new suites; TEST=mfib, this is invocation of the CLI command 'test mfib' which deals with many path add/remove, flag set/unset scenarios, TEST=ip-mcast, data-plane forwarding tests.
Updated applications to use the new MIFB functions;
- IPv6 NS/RA.
- DHCPv6
unit tests for these are undated accordingly.
Change-Id: I49ec37b01f1b170335a5697541c8fd30e6d3a961
Signed-off-by: Neale Ranns <nranns@cisco.com>
2016-11-22 17:07:28 +00:00
|
|
|
const char *g = match_input_with_format (input, f);
|
2016-08-15 11:12:27 -04:00
|
|
|
if (!g)
|
2015-12-08 15:45:58 -07:00
|
|
|
goto parse_fail;
|
|
|
|
|
last_non_white_space_match_format = g > f;
|
|
|
|
|
f = g;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
input_matches_format = 1;
|
2016-08-15 11:12:27 -04:00
|
|
|
parse_fail:
|
2015-12-08 15:45:58 -07:00
|
|
|
|
|
|
|
|
/* Rewind buffer marks. */
|
|
|
|
|
{
|
|
|
|
|
uword l = vec_len (input->buffer_marks);
|
|
|
|
|
|
|
|
|
|
/* If we did not match back up buffer to last mark. */
|
2016-08-15 11:12:27 -04:00
|
|
|
if (!input_matches_format)
|
|
|
|
|
input->index = input->buffer_marks[l - 1];
|
2015-12-08 15:45:58 -07:00
|
|
|
|
|
|
|
|
_vec_len (input->buffer_marks) = l - 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return input_matches_format;
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-17 13:32:25 +02:00
|
|
|
__clib_export uword
|
IP Multicast FIB (mfib)
- IPv[46] mfib tables with support for (*,G/m), (*,G) and (S,G) exact and longest prefix match
- Replication represented via a new replicate DPO.
- RPF configuration and data-plane checking
- data-plane signals sent to listening control planes.
The functions of multicast forwarding entries differ from their unicast conterparts, so we introduce a new mfib_table_t and mfib_entry_t objects. However, we re-use the fib_path_list to resolve and build the entry's output list. the fib_path_list provides the service to construct a replicate DPO for multicast.
'make tests' is added to with two new suites; TEST=mfib, this is invocation of the CLI command 'test mfib' which deals with many path add/remove, flag set/unset scenarios, TEST=ip-mcast, data-plane forwarding tests.
Updated applications to use the new MIFB functions;
- IPv6 NS/RA.
- DHCPv6
unit tests for these are undated accordingly.
Change-Id: I49ec37b01f1b170335a5697541c8fd30e6d3a961
Signed-off-by: Neale Ranns <nranns@cisco.com>
2016-11-22 17:07:28 +00:00
|
|
|
unformat (unformat_input_t * input, const char *fmt, ...)
|
2015-12-08 15:45:58 -07:00
|
|
|
{
|
|
|
|
|
va_list va;
|
|
|
|
|
uword result;
|
|
|
|
|
va_start (va, fmt);
|
|
|
|
|
result = va_unformat (input, fmt, &va);
|
|
|
|
|
va_end (va);
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-17 13:32:25 +02:00
|
|
|
__clib_export uword
|
2015-12-08 15:45:58 -07:00
|
|
|
unformat_user (unformat_input_t * input, unformat_function_t * func, ...)
|
|
|
|
|
{
|
|
|
|
|
va_list va;
|
|
|
|
|
uword result, l;
|
|
|
|
|
|
|
|
|
|
/* Save place in input buffer in case parse fails. */
|
|
|
|
|
l = vec_len (input->buffer_marks);
|
2016-08-15 11:12:27 -04:00
|
|
|
vec_add1_aligned (input->buffer_marks, input->index,
|
|
|
|
|
sizeof (input->buffer_marks[0]));
|
2015-12-08 15:45:58 -07:00
|
|
|
|
|
|
|
|
va_start (va, func);
|
|
|
|
|
result = func (input, &va);
|
|
|
|
|
va_end (va);
|
|
|
|
|
|
2016-10-26 14:03:20 -04:00
|
|
|
if (!result && input->index != UNFORMAT_END_OF_INPUT)
|
2015-12-08 15:45:58 -07:00
|
|
|
input->index = input->buffer_marks[l];
|
|
|
|
|
|
|
|
|
|
_vec_len (input->buffer_marks) = l;
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Setup for unformat of Unix style command line. */
|
2020-10-17 13:32:25 +02:00
|
|
|
__clib_export void
|
2016-08-15 11:12:27 -04:00
|
|
|
unformat_init_command_line (unformat_input_t * input, char *argv[])
|
2015-12-08 15:45:58 -07:00
|
|
|
{
|
|
|
|
|
uword i;
|
|
|
|
|
|
|
|
|
|
unformat_init (input, 0, 0);
|
|
|
|
|
|
|
|
|
|
/* Concatenate argument strings with space in between. */
|
|
|
|
|
for (i = 1; argv[i]; i++)
|
|
|
|
|
{
|
|
|
|
|
vec_add (input->buffer, argv[i], strlen (argv[i]));
|
|
|
|
|
if (argv[i + 1])
|
|
|
|
|
vec_add1 (input->buffer, ' ');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-17 13:32:25 +02:00
|
|
|
__clib_export void
|
2016-08-15 11:12:27 -04:00
|
|
|
unformat_init_string (unformat_input_t * input, char *string, int string_len)
|
2015-12-08 15:45:58 -07:00
|
|
|
{
|
|
|
|
|
unformat_init (input, 0, 0);
|
|
|
|
|
if (string_len > 0)
|
|
|
|
|
vec_add (input->buffer, string, string_len);
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-17 13:32:25 +02:00
|
|
|
__clib_export void
|
2016-08-15 11:12:27 -04:00
|
|
|
unformat_init_vector (unformat_input_t * input, u8 * vector_string)
|
2015-12-08 15:45:58 -07:00
|
|
|
{
|
|
|
|
|
unformat_init (input, 0, 0);
|
|
|
|
|
input->buffer = vector_string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef CLIB_UNIX
|
|
|
|
|
|
2016-08-15 11:12:27 -04:00
|
|
|
static uword
|
2017-09-10 15:04:27 -04:00
|
|
|
clib_file_fill_buffer (unformat_input_t * input)
|
2015-12-08 15:45:58 -07:00
|
|
|
{
|
|
|
|
|
int fd = pointer_to_uword (input->fill_buffer_arg);
|
|
|
|
|
uword l, n;
|
|
|
|
|
|
|
|
|
|
l = vec_len (input->buffer);
|
|
|
|
|
vec_resize (input->buffer, 4096);
|
|
|
|
|
n = read (fd, input->buffer + l, 4096);
|
|
|
|
|
if (n > 0)
|
|
|
|
|
_vec_len (input->buffer) = l + n;
|
|
|
|
|
|
|
|
|
|
if (n <= 0)
|
|
|
|
|
return UNFORMAT_END_OF_INPUT;
|
|
|
|
|
else
|
|
|
|
|
return input->index;
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-17 13:32:25 +02:00
|
|
|
__clib_export void
|
2017-09-10 15:04:27 -04:00
|
|
|
unformat_init_clib_file (unformat_input_t * input, int file_descriptor)
|
2015-12-08 15:45:58 -07:00
|
|
|
{
|
2017-09-10 15:04:27 -04:00
|
|
|
unformat_init (input, clib_file_fill_buffer,
|
2015-12-08 15:45:58 -07:00
|
|
|
uword_to_pointer (file_descriptor, void *));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Take input from Unix environment variable. */
|
2016-08-15 11:12:27 -04:00
|
|
|
uword
|
|
|
|
|
unformat_init_unix_env (unformat_input_t * input, char *var)
|
2015-12-08 15:45:58 -07:00
|
|
|
{
|
2016-08-15 11:12:27 -04:00
|
|
|
char *val = getenv (var);
|
2015-12-08 15:45:58 -07:00
|
|
|
if (val)
|
|
|
|
|
unformat_init_string (input, val, strlen (val));
|
|
|
|
|
return val != 0;
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-17 13:32:25 +02:00
|
|
|
__clib_export uword
|
2019-10-04 09:53:45 +00:00
|
|
|
unformat_data_size (unformat_input_t * input, va_list * args)
|
|
|
|
|
{
|
|
|
|
|
u64 _a;
|
|
|
|
|
u64 *a = va_arg (*args, u64 *);
|
|
|
|
|
if (unformat (input, "%lluGb", &_a))
|
|
|
|
|
*a = _a << 30;
|
|
|
|
|
else if (unformat (input, "%lluG", &_a))
|
|
|
|
|
*a = _a << 30;
|
|
|
|
|
else if (unformat (input, "%lluMb", &_a))
|
|
|
|
|
*a = _a << 20;
|
|
|
|
|
else if (unformat (input, "%lluM", &_a))
|
|
|
|
|
*a = _a << 20;
|
|
|
|
|
else if (unformat (input, "%lluKb", &_a))
|
|
|
|
|
*a = _a << 10;
|
|
|
|
|
else if (unformat (input, "%lluK", &_a))
|
|
|
|
|
*a = _a << 10;
|
|
|
|
|
else if (unformat (input, "%llu", a))
|
|
|
|
|
;
|
|
|
|
|
else
|
|
|
|
|
return 0;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-08 15:45:58 -07:00
|
|
|
#endif /* CLIB_UNIX */
|
|
|
|
|
|
2016-08-15 11:12:27 -04:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* fd.io coding-style-patch-verification: ON
|
|
|
|
|
*
|
|
|
|
|
* Local Variables:
|
|
|
|
|
* eval: (c-set-style "gnu")
|
|
|
|
|
* End:
|
|
|
|
|
*/
|